diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eedd0cf..30ff679 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,10 +20,10 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | @@ -40,14 +40,17 @@ jobs: build: timeout-minutes: 15 name: build + permissions: + contents: read + id-token: write runs-on: ${{ github.repository == 'stainless-sdks/cas-parser-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | @@ -61,16 +64,31 @@ jobs: - name: Build SDK run: ./scripts/build + - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/cas-parser-java' + id: github-oidc + uses: actions/github-script@v6 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Build and upload Maven artifacts + if: github.repository == 'stainless-sdks/cas-parser-java' + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + PROJECT: cas-parser-java + run: ./scripts/upload-artifacts test: timeout-minutes: 15 name: test runs-on: ${{ github.repository == 'stainless-sdks/cas-parser-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index 1b11f45..2bfe3c5 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -14,10 +14,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 87d49ed..a636804 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'CASParser/cas-parser-java' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Check release environment run: | diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2ed3b71..3d2ac0b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.0.4" + ".": "0.1.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 92721c7..968a0a4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 5 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cas-parser%2Fcas-parser-b7fdba3d3f97c7debc22c7ca30b828bce81bcd64648df8c94029b27a3321ebb9.yml -openapi_spec_hash: 03f1315f1d32ada42445ca920f047dff +configured_endpoints: 4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cas-parser%2Fcas-parser-ce2296c4b14d27c141bb2745607d2456c923fdca3ae0a0a0800c26e564333850.yml +openapi_spec_hash: 8eb586ccf16b534c0c15ff6a22274c7d config_hash: cb5d75abef6264b5d86448caf7295afa diff --git a/CHANGELOG.md b/CHANGELOG.md index f21b326..2b43336 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 0.1.0 (2026-01-20) + +Full Changelog: [v0.0.4...v0.1.0](https://github.com/CASParser/cas-parser-java/compare/v0.0.4...v0.1.0) + +### Features + +* **api:** api update ([1c7a4f1](https://github.com/CASParser/cas-parser-java/commit/1c7a4f1eebb4b336dc85f73a0319b48d568bf06c)) +* **api:** api update ([2e6c34f](https://github.com/CASParser/cas-parser-java/commit/2e6c34fbe30670c8ae1a74eb7f0f8fc5e8bb1890)) +* **api:** api update ([91a54b7](https://github.com/CASParser/cas-parser-java/commit/91a54b7acbf164ad459293fe697a4b0c9a795758)) +* **api:** api update ([557721f](https://github.com/CASParser/cas-parser-java/commit/557721f0775228db057005e912d8f820f512fcca)) +* **client:** expose sleeper option ([482319f](https://github.com/CASParser/cas-parser-java/commit/482319f0e19023df4e3ba5414e38914f6ad037fa)) + + +### Bug Fixes + +* **client:** deserialization of empty objects ([ce29632](https://github.com/CASParser/cas-parser-java/commit/ce29632f7f03c172ad042bbaa68e431ab2fd7fa7)) +* **client:** ensure single timer is created per client ([482319f](https://github.com/CASParser/cas-parser-java/commit/482319f0e19023df4e3ba5414e38914f6ad037fa)) +* **client:** incorrect `getPackageVersion` impl ([6772c5e](https://github.com/CASParser/cas-parser-java/commit/6772c5eeb5557a1e494852713cc55ec722b75145)) + + +### Chores + +* improve formatter performance ([692db64](https://github.com/CASParser/cas-parser-java/commit/692db64a36ef927e9c0ea23bd57192af99aaaf02)) + ## 0.0.4 (2025-09-13) Full Changelog: [v0.0.3...v0.0.4](https://github.com/CASParser/cas-parser-java/compare/v0.0.3...v0.0.4) diff --git a/LICENSE b/LICENSE index f1756ce..6bbb512 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Cas Parser + Copyright 2026 Cas Parser Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index eb1c0bb..bea2ccb 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.cas_parser.api/cas-parser-java)](https://central.sonatype.com/artifact/com.cas_parser.api/cas-parser-java/0.0.4) -[![javadoc](https://javadoc.io/badge2/com.cas_parser.api/cas-parser-java/0.0.4/javadoc.svg)](https://javadoc.io/doc/com.cas_parser.api/cas-parser-java/0.0.4) +[![Maven Central](https://img.shields.io/maven-central/v/com.cas_parser.api/cas-parser-java)](https://central.sonatype.com/artifact/com.cas_parser.api/cas-parser-java/0.1.0) +[![javadoc](https://javadoc.io/badge2/com.cas_parser.api/cas-parser-java/0.1.0/javadoc.svg)](https://javadoc.io/doc/com.cas_parser.api/cas-parser-java/0.1.0) @@ -11,9 +11,18 @@ The Cas Parser Java SDK provides convenient access to the [Cas Parser REST API]( It is generated with [Stainless](https://www.stainless.com/). +## MCP Server + +Use the Cas Parser MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. + +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=cas-parser-node-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsImNhcy1wYXJzZXItbm9kZS1tY3AiXX0) +[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22cas-parser-node-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22cas-parser-node-mcp%22%5D%7D) + +> Note: You may need to set environment variables in your MCP client. + -The REST API documentation can be found on [docs.casparser.in](https://docs.casparser.in/reference). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.cas_parser.api/cas-parser-java/0.0.4). +The REST API documentation can be found on [docs.casparser.in](https://docs.casparser.in/reference). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.cas_parser.api/cas-parser-java/0.1.0). @@ -24,7 +33,7 @@ The REST API documentation can be found on [docs.casparser.in](https://docs.casp ### Gradle ```kotlin -implementation("com.cas_parser.api:cas-parser-java:0.0.4") +implementation("com.cas_parser.api:cas-parser-java:0.1.0") ``` ### Maven @@ -33,7 +42,7 @@ implementation("com.cas_parser.api:cas-parser-java:0.0.4") com.cas_parser.api cas-parser-java - 0.0.4 + 0.1.0 ``` @@ -248,13 +257,13 @@ The SDK uses the standard [OkHttp logging interceptor](https://github.com/square Enable logging by setting the `CAS_PARSER_LOG` environment variable to `info`: ```sh -$ export CAS_PARSER_LOG=info +export CAS_PARSER_LOG=info ``` Or to `debug` for more verbose logging: ```sh -$ export CAS_PARSER_LOG=debug +export CAS_PARSER_LOG=debug ``` ## ProGuard and R8 @@ -274,6 +283,8 @@ If the SDK threw an exception, but you're _certain_ the version is compatible, t > [!CAUTION] > We make no guarantee that the SDK works correctly when the Jackson version check is disabled. +Also note that there are bugs in older Jackson versions that can affect the SDK. We don't work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead. + ## Network options ### Retries @@ -476,23 +487,6 @@ JsonValue complexValue = JsonValue.from(Map.of( )); ``` -Normally a `Builder` class's `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset. - -To forcibly omit a required parameter or property, pass [`JsonMissing`](cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Values.kt): - -```java -import com.cas_parser.api.core.JsonMissing; -import com.cas_parser.api.models.casgenerator.CasGeneratorGenerateCasParams; -import com.cas_parser.api.models.casparser.CasParserSmartParseParams; - -CasParserSmartParseParams params = CasGeneratorGenerateCasParams.builder() - .fromDate("2023-01-01") - .password("Abcdefghi12$") - .toDate("2023-12-31") - .email(JsonMissing.of()) - .build(); -``` - ### Response properties To access undocumented response properties, call the `_additionalProperties()` method: diff --git a/build.gradle.kts b/build.gradle.kts index d58d78e..30b3cae 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.cas_parser.api" - version = "0.0.4" // x-release-please-version + version = "0.1.0" // x-release-please-version } subprojects { diff --git a/buildSrc/src/main/kotlin/cas-parser.publish.gradle.kts b/buildSrc/src/main/kotlin/cas-parser.publish.gradle.kts index ef287d8..26aec10 100644 --- a/buildSrc/src/main/kotlin/cas-parser.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/cas-parser.publish.gradle.kts @@ -40,6 +40,14 @@ configure { } } } + repositories { + if (project.hasProperty("publishLocal")) { + maven { + name = "LocalFileSystem" + url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") + } + } + } } signing { diff --git a/cas-parser-java-client-okhttp/build.gradle.kts b/cas-parser-java-client-okhttp/build.gradle.kts index 115d28c..91df2a9 100644 --- a/cas-parser-java-client-okhttp/build.gradle.kts +++ b/cas-parser-java-client-okhttp/build.gradle.kts @@ -11,4 +11,5 @@ dependencies { testImplementation(kotlin("test")) testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2") } diff --git a/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClient.kt b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClient.kt index 687527a..93a7aeb 100644 --- a/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClient.kt +++ b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClient.kt @@ -5,6 +5,7 @@ package com.cas_parser.api.client.okhttp import com.cas_parser.api.client.CasParserClient import com.cas_parser.api.client.CasParserClientImpl import com.cas_parser.api.core.ClientOptions +import com.cas_parser.api.core.Sleeper import com.cas_parser.api.core.Timeout import com.cas_parser.api.core.http.Headers import com.cas_parser.api.core.http.HttpClient @@ -15,6 +16,7 @@ import java.net.Proxy import java.time.Clock import java.time.Duration import java.util.Optional +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -43,11 +45,31 @@ class CasParserOkHttpClient private constructor() { class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + /** + * The executor service to use for running HTTP requests. + * + * Defaults to OkHttp's + * [default executor service](https://github.com/square/okhttp/blob/ace792f443b2ffb17974f5c0d1cecdf589309f26/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt#L98-L104). + * + * This class takes ownership of the executor service and shuts it down when closed. + */ + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + + /** + * Alias for calling [Builder.dispatcherExecutorService] with + * `dispatcherExecutorService.orElse(null)`. + */ + fun dispatcherExecutorService(dispatcherExecutorService: Optional) = + dispatcherExecutorService(dispatcherExecutorService.getOrNull()) + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ @@ -120,6 +142,17 @@ class CasParserOkHttpClient private constructor() { */ fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) } + /** + * The interface to use for delaying execution, like during retries. + * + * This is primarily useful for using fake delays in tests. + * + * Defaults to real execution delays. + * + * This class takes ownership of the sleeper and closes it when closed. + */ + fun sleeper(sleeper: Sleeper) = apply { clientOptions.sleeper(sleeper) } + /** * The clock to use for operations that require timing, like retries. * @@ -285,6 +318,7 @@ class CasParserOkHttpClient private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) diff --git a/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClientAsync.kt b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClientAsync.kt index 186bbe4..f4858a0 100644 --- a/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClientAsync.kt +++ b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClientAsync.kt @@ -5,6 +5,7 @@ package com.cas_parser.api.client.okhttp import com.cas_parser.api.client.CasParserClientAsync import com.cas_parser.api.client.CasParserClientAsyncImpl import com.cas_parser.api.core.ClientOptions +import com.cas_parser.api.core.Sleeper import com.cas_parser.api.core.Timeout import com.cas_parser.api.core.http.Headers import com.cas_parser.api.core.http.HttpClient @@ -15,6 +16,7 @@ import java.net.Proxy import java.time.Clock import java.time.Duration import java.util.Optional +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -43,11 +45,31 @@ class CasParserOkHttpClientAsync private constructor() { class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + /** + * The executor service to use for running HTTP requests. + * + * Defaults to OkHttp's + * [default executor service](https://github.com/square/okhttp/blob/ace792f443b2ffb17974f5c0d1cecdf589309f26/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt#L98-L104). + * + * This class takes ownership of the executor service and shuts it down when closed. + */ + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + + /** + * Alias for calling [Builder.dispatcherExecutorService] with + * `dispatcherExecutorService.orElse(null)`. + */ + fun dispatcherExecutorService(dispatcherExecutorService: Optional) = + dispatcherExecutorService(dispatcherExecutorService.getOrNull()) + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ @@ -120,6 +142,17 @@ class CasParserOkHttpClientAsync private constructor() { */ fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) } + /** + * The interface to use for delaying execution, like during retries. + * + * This is primarily useful for using fake delays in tests. + * + * Defaults to real execution delays. + * + * This class takes ownership of the sleeper and closes it when closed. + */ + fun sleeper(sleeper: Sleeper) = apply { clientOptions.sleeper(sleeper) } + /** * The clock to use for operations that require timing, like retries. * @@ -285,6 +318,7 @@ class CasParserOkHttpClientAsync private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) diff --git a/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/OkHttpClient.kt b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/OkHttpClient.kt index 281e1c4..7079d3c 100644 --- a/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/OkHttpClient.kt +++ b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/OkHttpClient.kt @@ -13,12 +13,15 @@ import java.io.IOException import java.io.InputStream import java.net.Proxy import java.time.Duration +import java.util.concurrent.CancellationException import java.util.concurrent.CompletableFuture +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager import okhttp3.Call import okhttp3.Callback +import okhttp3.Dispatcher import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType @@ -29,8 +32,8 @@ import okhttp3.Response import okhttp3.logging.HttpLoggingInterceptor import okio.BufferedSink -class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpClient) : - HttpClient { +class OkHttpClient +private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClient) : HttpClient { override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { val call = newCall(request, requestOptions) @@ -50,20 +53,25 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC ): CompletableFuture { val future = CompletableFuture() - request.body?.run { future.whenComplete { _, _ -> close() } } - - newCall(request, requestOptions) - .enqueue( - object : Callback { - override fun onResponse(call: Call, response: Response) { - future.complete(response.toResponse()) - } + val call = newCall(request, requestOptions) + call.enqueue( + object : Callback { + override fun onResponse(call: Call, response: Response) { + future.complete(response.toResponse()) + } - override fun onFailure(call: Call, e: IOException) { - future.completeExceptionally(CasParserIoException("Request failed", e)) - } + override fun onFailure(call: Call, e: IOException) { + future.completeExceptionally(CasParserIoException("Request failed", e)) } - ) + } + ) + + future.whenComplete { _, e -> + if (e is CancellationException) { + call.cancel() + } + request.body?.close() + } return future } @@ -109,19 +117,19 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC val builder = Request.Builder().url(toUrl()).method(method.name, body) headers.names().forEach { name -> - headers.values(name).forEach { builder.header(name, it) } + headers.values(name).forEach { builder.addHeader(name, it) } } if ( !headers.names().contains("X-Stainless-Read-Timeout") && client.readTimeoutMillis != 0 ) { - builder.header( + builder.addHeader( "X-Stainless-Read-Timeout", Duration.ofMillis(client.readTimeoutMillis.toLong()).seconds.toString(), ) } if (!headers.names().contains("X-Stainless-Timeout") && client.callTimeoutMillis != 0) { - builder.header( + builder.addHeader( "X-Stainless-Timeout", Duration.ofMillis(client.callTimeoutMillis.toLong()).seconds.toString(), ) @@ -192,6 +200,7 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC private var timeout: Timeout = Timeout.default() private var proxy: Proxy? = null + private var dispatcherExecutorService: ExecutorService? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null @@ -202,6 +211,10 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply { this.sslSocketFactory = sslSocketFactory } @@ -217,12 +230,16 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC fun build(): OkHttpClient = OkHttpClient( okhttp3.OkHttpClient.Builder() + // `RetryingHttpClient` handles retries if the user enabled them. + .retryOnConnectionFailure(false) .connectTimeout(timeout.connect()) .readTimeout(timeout.read()) .writeTimeout(timeout.write()) .callTimeout(timeout.request()) .proxy(proxy) .apply { + dispatcherExecutorService?.let { dispatcher(Dispatcher(it)) } + val sslSocketFactory = sslSocketFactory val trustManager = trustManager if (sslSocketFactory != null && trustManager != null) { diff --git a/cas-parser-java-client-okhttp/src/test/kotlin/com/cas_parser/api/client/okhttp/OkHttpClientTest.kt b/cas-parser-java-client-okhttp/src/test/kotlin/com/cas_parser/api/client/okhttp/OkHttpClientTest.kt new file mode 100644 index 0000000..457b40c --- /dev/null +++ b/cas-parser-java-client-okhttp/src/test/kotlin/com/cas_parser/api/client/okhttp/OkHttpClientTest.kt @@ -0,0 +1,44 @@ +package com.cas_parser.api.client.okhttp + +import com.cas_parser.api.core.http.HttpMethod +import com.cas_parser.api.core.http.HttpRequest +import com.github.tomakehurst.wiremock.client.WireMock.* +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo +import com.github.tomakehurst.wiremock.junit5.WireMockTest +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.parallel.ResourceLock + +@WireMockTest +@ResourceLock("https://github.com/wiremock/wiremock/issues/169") +internal class OkHttpClientTest { + + private lateinit var baseUrl: String + private lateinit var httpClient: OkHttpClient + + @BeforeEach + fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { + baseUrl = wmRuntimeInfo.httpBaseUrl + httpClient = OkHttpClient.builder().build() + } + + @Test + fun executeAsync_whenFutureCancelled_cancelsUnderlyingCall() { + stubFor(post(urlPathEqualTo("/something")).willReturn(ok())) + val responseFuture = + httpClient.executeAsync( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build() + ) + val call = httpClient.okHttpClient.dispatcher.runningCalls().single() + + responseFuture.cancel(false) + + // Should have cancelled the underlying call + assertThat(call.isCanceled()).isTrue() + } +} diff --git a/cas-parser-java-core/build.gradle.kts b/cas-parser-java-core/build.gradle.kts index 9861d5b..7d1eeed 100644 --- a/cas-parser-java-core/build.gradle.kts +++ b/cas-parser-java-core/build.gradle.kts @@ -5,14 +5,16 @@ plugins { configurations.all { resolutionStrategy { - // Compile and test against a lower Jackson version to ensure we're compatible with it. - // We publish with a higher version (see below) to ensure users depend on a secure version by default. - force("com.fasterxml.jackson.core:jackson-core:2.13.4") - force("com.fasterxml.jackson.core:jackson-databind:2.13.4") - force("com.fasterxml.jackson.core:jackson-annotations:2.13.4") - force("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.4") - force("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4") - force("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") + // Compile and test against a lower Jackson version to ensure we're compatible with it. Note that + // we generally support 2.13.4, but test against 2.14.0 because 2.13.4 has some annoying (but + // niche) bugs (users should upgrade if they encounter them). We publish with a higher version + // (see below) to ensure users depend on a secure version by default. + force("com.fasterxml.jackson.core:jackson-core:2.14.0") + force("com.fasterxml.jackson.core:jackson-databind:2.14.0") + force("com.fasterxml.jackson.core:jackson-annotations:2.14.0") + force("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.0") + force("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.0") + force("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.0") } } diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ClientOptions.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ClientOptions.kt index d330bc7..f5195cd 100644 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ClientOptions.kt +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ClientOptions.kt @@ -40,6 +40,16 @@ private constructor( * rarely needs to be overridden. */ @get:JvmName("jsonMapper") val jsonMapper: JsonMapper, + /** + * The interface to use for delaying execution, like during retries. + * + * This is primarily useful for using fake delays in tests. + * + * Defaults to real execution delays. + * + * This class takes ownership of the sleeper and closes it when closed. + */ + @get:JvmName("sleeper") val sleeper: Sleeper, /** * The clock to use for operations that require timing, like retries. * @@ -131,6 +141,7 @@ private constructor( private var httpClient: HttpClient? = null private var checkJacksonVersionCompatibility: Boolean = true private var jsonMapper: JsonMapper = jsonMapper() + private var sleeper: Sleeper? = null private var clock: Clock = Clock.systemUTC() private var baseUrl: String? = null private var headers: Headers.Builder = Headers.builder() @@ -145,6 +156,7 @@ private constructor( httpClient = clientOptions.originalHttpClient checkJacksonVersionCompatibility = clientOptions.checkJacksonVersionCompatibility jsonMapper = clientOptions.jsonMapper + sleeper = clientOptions.sleeper clock = clientOptions.clock baseUrl = clientOptions.baseUrl headers = clientOptions.headers.toBuilder() @@ -185,6 +197,17 @@ private constructor( */ fun jsonMapper(jsonMapper: JsonMapper) = apply { this.jsonMapper = jsonMapper } + /** + * The interface to use for delaying execution, like during retries. + * + * This is primarily useful for using fake delays in tests. + * + * Defaults to real execution delays. + * + * This class takes ownership of the sleeper and closes it when closed. + */ + fun sleeper(sleeper: Sleeper) = apply { this.sleeper = PhantomReachableSleeper(sleeper) } + /** * The clock to use for operations that require timing, like retries. * @@ -369,6 +392,7 @@ private constructor( */ fun build(): ClientOptions { val httpClient = checkRequired("httpClient", httpClient) + val sleeper = sleeper ?: PhantomReachableSleeper(DefaultSleeper()) val apiKey = checkRequired("apiKey", apiKey) val headers = Headers.builder() @@ -392,11 +416,13 @@ private constructor( httpClient, RetryingHttpClient.builder() .httpClient(httpClient) + .sleeper(sleeper) .clock(clock) .maxRetries(maxRetries) .build(), checkJacksonVersionCompatibility, jsonMapper, + sleeper, clock, baseUrl, headers.build(), @@ -421,5 +447,6 @@ private constructor( */ fun close() { httpClient.close() + sleeper.close() } } diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/DefaultSleeper.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/DefaultSleeper.kt new file mode 100644 index 0000000..5e092e2 --- /dev/null +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/DefaultSleeper.kt @@ -0,0 +1,28 @@ +package com.cas_parser.api.core + +import java.time.Duration +import java.util.Timer +import java.util.TimerTask +import java.util.concurrent.CompletableFuture + +class DefaultSleeper : Sleeper { + + private val timer = Timer("DefaultSleeper", true) + + override fun sleep(duration: Duration) = Thread.sleep(duration.toMillis()) + + override fun sleepAsync(duration: Duration): CompletableFuture { + val future = CompletableFuture() + timer.schedule( + object : TimerTask() { + override fun run() { + future.complete(null) + } + }, + duration.toMillis(), + ) + return future + } + + override fun close() = timer.cancel() +} diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ObjectMappers.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ObjectMappers.kt index 85d0b7e..9096f88 100644 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ObjectMappers.kt +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ObjectMappers.kt @@ -24,6 +24,7 @@ import java.io.InputStream import java.time.DateTimeException import java.time.LocalDate import java.time.LocalDateTime +import java.time.OffsetDateTime import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.time.temporal.ChronoField @@ -36,7 +37,7 @@ fun jsonMapper(): JsonMapper = .addModule( SimpleModule() .addSerializer(InputStreamSerializer) - .addDeserializer(LocalDateTime::class.java, LenientLocalDateTimeDeserializer()) + .addDeserializer(OffsetDateTime::class.java, LenientOffsetDateTimeDeserializer()) ) .withCoercionConfig(LogicalType.Boolean) { it.setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) @@ -47,6 +48,7 @@ fun jsonMapper(): JsonMapper = } .withCoercionConfig(LogicalType.Integer) { it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) .setCoercion(CoercionInputShape.String, CoercionAction.Fail) .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) @@ -64,6 +66,12 @@ fun jsonMapper(): JsonMapper = .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) } + .withCoercionConfig(LogicalType.DateTime) { + it.setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) + } .withCoercionConfig(LogicalType.Array) { it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) @@ -124,10 +132,10 @@ private object InputStreamSerializer : BaseSerializer(InputStream:: } /** - * A deserializer that can deserialize [LocalDateTime] from datetimes, dates, and zoned datetimes. + * A deserializer that can deserialize [OffsetDateTime] from datetimes, dates, and zoned datetimes. */ -private class LenientLocalDateTimeDeserializer : - StdDeserializer(LocalDateTime::class.java) { +private class LenientOffsetDateTimeDeserializer : + StdDeserializer(OffsetDateTime::class.java) { companion object { @@ -141,7 +149,7 @@ private class LenientLocalDateTimeDeserializer : override fun logicalType(): LogicalType = LogicalType.DateTime - override fun deserialize(p: JsonParser, context: DeserializationContext?): LocalDateTime { + override fun deserialize(p: JsonParser, context: DeserializationContext): OffsetDateTime { val exceptions = mutableListOf() for (formatter in DATE_TIME_FORMATTERS) { @@ -149,18 +157,20 @@ private class LenientLocalDateTimeDeserializer : val temporal = formatter.parse(p.text) return when { - !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> - LocalDate.from(temporal).atStartOfDay() - !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> - LocalDateTime.from(temporal) - else -> ZonedDateTime.from(temporal).toLocalDateTime() - } + !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> + LocalDate.from(temporal).atStartOfDay() + !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> + LocalDateTime.from(temporal) + else -> ZonedDateTime.from(temporal).toLocalDateTime() + } + .atZone(context.timeZone.toZoneId()) + .toOffsetDateTime() } catch (e: DateTimeException) { exceptions.add(e) } } - throw JsonParseException(p, "Cannot parse `LocalDateTime` from value: ${p.text}").apply { + throw JsonParseException(p, "Cannot parse `OffsetDateTime` from value: ${p.text}").apply { exceptions.forEach { addSuppressed(it) } } } diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/PhantomReachableSleeper.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/PhantomReachableSleeper.kt new file mode 100644 index 0000000..2b3afd5 --- /dev/null +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/PhantomReachableSleeper.kt @@ -0,0 +1,23 @@ +package com.cas_parser.api.core + +import java.time.Duration +import java.util.concurrent.CompletableFuture + +/** + * A delegating wrapper around a [Sleeper] that closes it once it's only phantom reachable. + * + * This class ensures the [Sleeper] is closed even if the user forgets to do it. + */ +internal class PhantomReachableSleeper(private val sleeper: Sleeper) : Sleeper { + + init { + closeWhenPhantomReachable(this, sleeper) + } + + override fun sleep(duration: Duration) = sleeper.sleep(duration) + + override fun sleepAsync(duration: Duration): CompletableFuture = + sleeper.sleepAsync(duration) + + override fun close() = sleeper.close() +} diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Properties.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Properties.kt index c715f1a..dc9a375 100644 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Properties.kt +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Properties.kt @@ -2,7 +2,7 @@ package com.cas_parser.api.core -import java.util.Properties +import com.cas_parser.api.client.CasParserClient fun getOsArch(): String { val osArch = System.getProperty("os.arch") @@ -16,7 +16,7 @@ fun getOsArch(): String { "x86_64" -> "x64" "arm" -> "arm" "aarch64" -> "arm64" - else -> "other:${osArch}" + else -> "other:$osArch" } } @@ -30,13 +30,13 @@ fun getOsName(): String { osName.startsWith("Linux") -> "Linux" osName.startsWith("Mac OS") -> "MacOS" osName.startsWith("Windows") -> "Windows" - else -> "Other:${osName}" + else -> "Other:$osName" } } fun getOsVersion(): String = System.getProperty("os.version", "unknown") fun getPackageVersion(): String = - Properties::class.java.`package`.implementationVersion ?: "unknown" + CasParserClient::class.java.`package`.implementationVersion ?: "unknown" fun getJavaVersion(): String = System.getProperty("java.version", "unknown") diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Sleeper.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Sleeper.kt new file mode 100644 index 0000000..5a93d9a --- /dev/null +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Sleeper.kt @@ -0,0 +1,21 @@ +package com.cas_parser.api.core + +import java.time.Duration +import java.util.concurrent.CompletableFuture + +/** + * An interface for delaying execution for a specified amount of time. + * + * Useful for testing and cleaning up resources. + */ +interface Sleeper : AutoCloseable { + + /** Synchronously pauses execution for the given [duration]. */ + fun sleep(duration: Duration) + + /** Asynchronously pauses execution for the given [duration]. */ + fun sleepAsync(duration: Duration): CompletableFuture + + /** Overridden from [AutoCloseable] to not have a checked exception in its signature. */ + override fun close() +} diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/HttpRequest.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/HttpRequest.kt index 7301769..9679caa 100644 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/HttpRequest.kt +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/HttpRequest.kt @@ -2,6 +2,7 @@ package com.cas_parser.api.core.http import com.cas_parser.api.core.checkRequired import com.cas_parser.api.core.toImmutable +import java.net.URLEncoder class HttpRequest private constructor( @@ -13,6 +14,35 @@ private constructor( @get:JvmName("body") val body: HttpRequestBody?, ) { + fun url(): String = buildString { + append(baseUrl) + + pathSegments.forEach { segment -> + if (!endsWith("/")) { + append("/") + } + append(URLEncoder.encode(segment, "UTF-8")) + } + + if (queryParams.isEmpty()) { + return@buildString + } + + append("?") + var isFirst = true + queryParams.keys().forEach { key -> + queryParams.values(key).forEach { value -> + if (!isFirst) { + append("&") + } + append(URLEncoder.encode(key, "UTF-8")) + append("=") + append(URLEncoder.encode(value, "UTF-8")) + isFirst = false + } + } + } + fun toBuilder(): Builder = Builder().from(this) override fun toString(): String = diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/RetryingHttpClient.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/RetryingHttpClient.kt index 569b1aa..3f34f6e 100644 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/RetryingHttpClient.kt +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/RetryingHttpClient.kt @@ -1,6 +1,8 @@ package com.cas_parser.api.core.http +import com.cas_parser.api.core.DefaultSleeper import com.cas_parser.api.core.RequestOptions +import com.cas_parser.api.core.Sleeper import com.cas_parser.api.core.checkRequired import com.cas_parser.api.errors.CasParserIoException import com.cas_parser.api.errors.CasParserRetryableException @@ -11,8 +13,6 @@ import java.time.OffsetDateTime import java.time.format.DateTimeFormatter import java.time.format.DateTimeParseException import java.time.temporal.ChronoUnit -import java.util.Timer -import java.util.TimerTask import java.util.UUID import java.util.concurrent.CompletableFuture import java.util.concurrent.ThreadLocalRandom @@ -31,10 +31,6 @@ private constructor( ) : HttpClient { override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { - if (!isRetryable(request) || maxRetries <= 0) { - return httpClient.execute(request, requestOptions) - } - var modifiedRequest = maybeAddIdempotencyHeader(request) // Don't send the current retry count in the headers if the caller set their own value. @@ -48,6 +44,10 @@ private constructor( modifiedRequest = setRetryCountHeader(modifiedRequest, retries) } + if (!isRetryable(modifiedRequest)) { + return httpClient.execute(modifiedRequest, requestOptions) + } + val response = try { val response = httpClient.execute(modifiedRequest, requestOptions) @@ -75,10 +75,6 @@ private constructor( request: HttpRequest, requestOptions: RequestOptions, ): CompletableFuture { - if (!isRetryable(request) || maxRetries <= 0) { - return httpClient.executeAsync(request, requestOptions) - } - val modifiedRequest = maybeAddIdempotencyHeader(request) // Don't send the current retry count in the headers if the caller set their own value. @@ -94,8 +90,12 @@ private constructor( val requestWithRetryCount = if (shouldSendRetryCount) setRetryCountHeader(request, retries) else request - return httpClient - .executeAsync(requestWithRetryCount, requestOptions) + val responseFuture = httpClient.executeAsync(requestWithRetryCount, requestOptions) + if (!isRetryable(requestWithRetryCount)) { + return responseFuture + } + + return responseFuture .handleAsync( fun( response: HttpResponse?, @@ -130,7 +130,10 @@ private constructor( return executeWithRetries(modifiedRequest, requestOptions) } - override fun close() = httpClient.close() + override fun close() { + httpClient.close() + sleeper.close() + } private fun isRetryable(request: HttpRequest): Boolean = // Some requests, such as when a request body is being streamed, cannot be retried because @@ -235,33 +238,14 @@ private constructor( class Builder internal constructor() { private var httpClient: HttpClient? = null - private var sleeper: Sleeper = - object : Sleeper { - - private val timer = Timer("RetryingHttpClient", true) - - override fun sleep(duration: Duration) = Thread.sleep(duration.toMillis()) - - override fun sleepAsync(duration: Duration): CompletableFuture { - val future = CompletableFuture() - timer.schedule( - object : TimerTask() { - override fun run() { - future.complete(null) - } - }, - duration.toMillis(), - ) - return future - } - } + private var sleeper: Sleeper? = null private var clock: Clock = Clock.systemUTC() private var maxRetries: Int = 2 private var idempotencyHeader: String? = null fun httpClient(httpClient: HttpClient) = apply { this.httpClient = httpClient } - @JvmSynthetic internal fun sleeper(sleeper: Sleeper) = apply { this.sleeper = sleeper } + fun sleeper(sleeper: Sleeper) = apply { this.sleeper = sleeper } fun clock(clock: Clock) = apply { this.clock = clock } @@ -272,17 +256,10 @@ private constructor( fun build(): HttpClient = RetryingHttpClient( checkRequired("httpClient", httpClient), - sleeper, + sleeper ?: DefaultSleeper(), clock, maxRetries, idempotencyHeader, ) } - - internal interface Sleeper { - - fun sleep(duration: Duration) - - fun sleepAsync(duration: Duration): CompletableFuture - } } diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasParams.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasParams.kt deleted file mode 100644 index eb7213c..0000000 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasParams.kt +++ /dev/null @@ -1,918 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.cas_parser.api.models.casgenerator - -import com.cas_parser.api.core.Enum -import com.cas_parser.api.core.ExcludeMissing -import com.cas_parser.api.core.JsonField -import com.cas_parser.api.core.JsonMissing -import com.cas_parser.api.core.JsonValue -import com.cas_parser.api.core.Params -import com.cas_parser.api.core.checkRequired -import com.cas_parser.api.core.http.Headers -import com.cas_parser.api.core.http.QueryParams -import com.cas_parser.api.errors.CasParserInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects -import java.util.Optional -import kotlin.jvm.optionals.getOrNull - -/** - * This endpoint generates CAS (Consolidated Account Statement) documents by submitting a mailback - * request to the specified CAS authority. Currently only supports KFintech, with plans to support - * CAMS, CDSL, and NSDL in the future. - */ -class CasGeneratorGenerateCasParams -private constructor( - private val body: Body, - private val additionalHeaders: Headers, - private val additionalQueryParams: QueryParams, -) : Params { - - /** - * Email address to receive the CAS document - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun email(): String = body.email() - - /** - * Start date for the CAS period (format YYYY-MM-DD) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun fromDate(): String = body.fromDate() - - /** - * Password to protect the generated CAS PDF - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun password(): String = body.password() - - /** - * End date for the CAS period (format YYYY-MM-DD) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun toDate(): String = body.toDate() - - /** - * CAS authority to generate the document from (currently only kfintech is supported) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun casAuthority(): Optional = body.casAuthority() - - /** - * PAN number (optional for some CAS authorities) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun panNo(): Optional = body.panNo() - - /** - * Returns the raw JSON value of [email]. - * - * Unlike [email], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _email(): JsonField = body._email() - - /** - * Returns the raw JSON value of [fromDate]. - * - * Unlike [fromDate], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _fromDate(): JsonField = body._fromDate() - - /** - * Returns the raw JSON value of [password]. - * - * Unlike [password], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _password(): JsonField = body._password() - - /** - * Returns the raw JSON value of [toDate]. - * - * Unlike [toDate], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _toDate(): JsonField = body._toDate() - - /** - * Returns the raw JSON value of [casAuthority]. - * - * Unlike [casAuthority], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _casAuthority(): JsonField = body._casAuthority() - - /** - * Returns the raw JSON value of [panNo]. - * - * Unlike [panNo], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _panNo(): JsonField = body._panNo() - - fun _additionalBodyProperties(): Map = body._additionalProperties() - - /** Additional headers to send with the request. */ - fun _additionalHeaders(): Headers = additionalHeaders - - /** Additional query param to send with the request. */ - fun _additionalQueryParams(): QueryParams = additionalQueryParams - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [CasGeneratorGenerateCasParams]. - * - * The following fields are required: - * ```java - * .email() - * .fromDate() - * .password() - * .toDate() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [CasGeneratorGenerateCasParams]. */ - class Builder internal constructor() { - - private var body: Body.Builder = Body.builder() - private var additionalHeaders: Headers.Builder = Headers.builder() - private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - - @JvmSynthetic - internal fun from(casGeneratorGenerateCasParams: CasGeneratorGenerateCasParams) = apply { - body = casGeneratorGenerateCasParams.body.toBuilder() - additionalHeaders = casGeneratorGenerateCasParams.additionalHeaders.toBuilder() - additionalQueryParams = casGeneratorGenerateCasParams.additionalQueryParams.toBuilder() - } - - /** - * Sets the entire request body. - * - * This is generally only useful if you are already constructing the body separately. - * Otherwise, it's more convenient to use the top-level setters instead: - * - [email] - * - [fromDate] - * - [password] - * - [toDate] - * - [casAuthority] - * - etc. - */ - fun body(body: Body) = apply { this.body = body.toBuilder() } - - /** Email address to receive the CAS document */ - fun email(email: String) = apply { body.email(email) } - - /** - * Sets [Builder.email] to an arbitrary JSON value. - * - * You should usually call [Builder.email] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun email(email: JsonField) = apply { body.email(email) } - - /** Start date for the CAS period (format YYYY-MM-DD) */ - fun fromDate(fromDate: String) = apply { body.fromDate(fromDate) } - - /** - * Sets [Builder.fromDate] to an arbitrary JSON value. - * - * You should usually call [Builder.fromDate] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun fromDate(fromDate: JsonField) = apply { body.fromDate(fromDate) } - - /** Password to protect the generated CAS PDF */ - fun password(password: String) = apply { body.password(password) } - - /** - * Sets [Builder.password] to an arbitrary JSON value. - * - * You should usually call [Builder.password] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun password(password: JsonField) = apply { body.password(password) } - - /** End date for the CAS period (format YYYY-MM-DD) */ - fun toDate(toDate: String) = apply { body.toDate(toDate) } - - /** - * Sets [Builder.toDate] to an arbitrary JSON value. - * - * You should usually call [Builder.toDate] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun toDate(toDate: JsonField) = apply { body.toDate(toDate) } - - /** CAS authority to generate the document from (currently only kfintech is supported) */ - fun casAuthority(casAuthority: CasAuthority) = apply { body.casAuthority(casAuthority) } - - /** - * Sets [Builder.casAuthority] to an arbitrary JSON value. - * - * You should usually call [Builder.casAuthority] with a well-typed [CasAuthority] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun casAuthority(casAuthority: JsonField) = apply { - body.casAuthority(casAuthority) - } - - /** PAN number (optional for some CAS authorities) */ - fun panNo(panNo: String) = apply { body.panNo(panNo) } - - /** - * Sets [Builder.panNo] to an arbitrary JSON value. - * - * You should usually call [Builder.panNo] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun panNo(panNo: JsonField) = apply { body.panNo(panNo) } - - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - body.additionalProperties(additionalBodyProperties) - } - - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - body.putAdditionalProperty(key, value) - } - - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - body.putAllAdditionalProperties(additionalBodyProperties) - } - - fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - - fun removeAllAdditionalBodyProperties(keys: Set) = apply { - body.removeAllAdditionalProperties(keys) - } - - fun additionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun putAdditionalHeader(name: String, value: String) = apply { - additionalHeaders.put(name, value) - } - - fun putAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.put(name, values) - } - - fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun replaceAdditionalHeaders(name: String, value: String) = apply { - additionalHeaders.replace(name, value) - } - - fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.replace(name, values) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - - fun removeAllAdditionalHeaders(names: Set) = apply { - additionalHeaders.removeAll(names) - } - - fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun putAdditionalQueryParam(key: String, value: String) = apply { - additionalQueryParams.put(key, value) - } - - fun putAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.put(key, values) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun replaceAdditionalQueryParams(key: String, value: String) = apply { - additionalQueryParams.replace(key, value) - } - - fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.replace(key, values) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - - fun removeAllAdditionalQueryParams(keys: Set) = apply { - additionalQueryParams.removeAll(keys) - } - - /** - * Returns an immutable instance of [CasGeneratorGenerateCasParams]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .email() - * .fromDate() - * .password() - * .toDate() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): CasGeneratorGenerateCasParams = - CasGeneratorGenerateCasParams( - body.build(), - additionalHeaders.build(), - additionalQueryParams.build(), - ) - } - - fun _body(): Body = body - - override fun _headers(): Headers = additionalHeaders - - override fun _queryParams(): QueryParams = additionalQueryParams - - class Body - private constructor( - private val email: JsonField, - private val fromDate: JsonField, - private val password: JsonField, - private val toDate: JsonField, - private val casAuthority: JsonField, - private val panNo: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("email") @ExcludeMissing email: JsonField = JsonMissing.of(), - @JsonProperty("from_date") - @ExcludeMissing - fromDate: JsonField = JsonMissing.of(), - @JsonProperty("password") - @ExcludeMissing - password: JsonField = JsonMissing.of(), - @JsonProperty("to_date") @ExcludeMissing toDate: JsonField = JsonMissing.of(), - @JsonProperty("cas_authority") - @ExcludeMissing - casAuthority: JsonField = JsonMissing.of(), - @JsonProperty("pan_no") @ExcludeMissing panNo: JsonField = JsonMissing.of(), - ) : this(email, fromDate, password, toDate, casAuthority, panNo, mutableMapOf()) - - /** - * Email address to receive the CAS document - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun email(): String = email.getRequired("email") - - /** - * Start date for the CAS period (format YYYY-MM-DD) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun fromDate(): String = fromDate.getRequired("from_date") - - /** - * Password to protect the generated CAS PDF - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun password(): String = password.getRequired("password") - - /** - * End date for the CAS period (format YYYY-MM-DD) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun toDate(): String = toDate.getRequired("to_date") - - /** - * CAS authority to generate the document from (currently only kfintech is supported) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun casAuthority(): Optional = casAuthority.getOptional("cas_authority") - - /** - * PAN number (optional for some CAS authorities) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun panNo(): Optional = panNo.getOptional("pan_no") - - /** - * Returns the raw JSON value of [email]. - * - * Unlike [email], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("email") @ExcludeMissing fun _email(): JsonField = email - - /** - * Returns the raw JSON value of [fromDate]. - * - * Unlike [fromDate], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("from_date") @ExcludeMissing fun _fromDate(): JsonField = fromDate - - /** - * Returns the raw JSON value of [password]. - * - * Unlike [password], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("password") @ExcludeMissing fun _password(): JsonField = password - - /** - * Returns the raw JSON value of [toDate]. - * - * Unlike [toDate], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("to_date") @ExcludeMissing fun _toDate(): JsonField = toDate - - /** - * Returns the raw JSON value of [casAuthority]. - * - * Unlike [casAuthority], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("cas_authority") - @ExcludeMissing - fun _casAuthority(): JsonField = casAuthority - - /** - * Returns the raw JSON value of [panNo]. - * - * Unlike [panNo], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("pan_no") @ExcludeMissing fun _panNo(): JsonField = panNo - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Body]. - * - * The following fields are required: - * ```java - * .email() - * .fromDate() - * .password() - * .toDate() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Body]. */ - class Builder internal constructor() { - - private var email: JsonField? = null - private var fromDate: JsonField? = null - private var password: JsonField? = null - private var toDate: JsonField? = null - private var casAuthority: JsonField = JsonMissing.of() - private var panNo: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(body: Body) = apply { - email = body.email - fromDate = body.fromDate - password = body.password - toDate = body.toDate - casAuthority = body.casAuthority - panNo = body.panNo - additionalProperties = body.additionalProperties.toMutableMap() - } - - /** Email address to receive the CAS document */ - fun email(email: String) = email(JsonField.of(email)) - - /** - * Sets [Builder.email] to an arbitrary JSON value. - * - * You should usually call [Builder.email] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun email(email: JsonField) = apply { this.email = email } - - /** Start date for the CAS period (format YYYY-MM-DD) */ - fun fromDate(fromDate: String) = fromDate(JsonField.of(fromDate)) - - /** - * Sets [Builder.fromDate] to an arbitrary JSON value. - * - * You should usually call [Builder.fromDate] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun fromDate(fromDate: JsonField) = apply { this.fromDate = fromDate } - - /** Password to protect the generated CAS PDF */ - fun password(password: String) = password(JsonField.of(password)) - - /** - * Sets [Builder.password] to an arbitrary JSON value. - * - * You should usually call [Builder.password] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun password(password: JsonField) = apply { this.password = password } - - /** End date for the CAS period (format YYYY-MM-DD) */ - fun toDate(toDate: String) = toDate(JsonField.of(toDate)) - - /** - * Sets [Builder.toDate] to an arbitrary JSON value. - * - * You should usually call [Builder.toDate] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun toDate(toDate: JsonField) = apply { this.toDate = toDate } - - /** - * CAS authority to generate the document from (currently only kfintech is supported) - */ - fun casAuthority(casAuthority: CasAuthority) = casAuthority(JsonField.of(casAuthority)) - - /** - * Sets [Builder.casAuthority] to an arbitrary JSON value. - * - * You should usually call [Builder.casAuthority] with a well-typed [CasAuthority] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun casAuthority(casAuthority: JsonField) = apply { - this.casAuthority = casAuthority - } - - /** PAN number (optional for some CAS authorities) */ - fun panNo(panNo: String) = panNo(JsonField.of(panNo)) - - /** - * Sets [Builder.panNo] to an arbitrary JSON value. - * - * You should usually call [Builder.panNo] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun panNo(panNo: JsonField) = apply { this.panNo = panNo } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Body]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .email() - * .fromDate() - * .password() - * .toDate() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): Body = - Body( - checkRequired("email", email), - checkRequired("fromDate", fromDate), - checkRequired("password", password), - checkRequired("toDate", toDate), - casAuthority, - panNo, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Body = apply { - if (validated) { - return@apply - } - - email() - fromDate() - password() - toDate() - casAuthority().ifPresent { it.validate() } - panNo() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (email.asKnown().isPresent) 1 else 0) + - (if (fromDate.asKnown().isPresent) 1 else 0) + - (if (password.asKnown().isPresent) 1 else 0) + - (if (toDate.asKnown().isPresent) 1 else 0) + - (casAuthority.asKnown().getOrNull()?.validity() ?: 0) + - (if (panNo.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Body && - email == other.email && - fromDate == other.fromDate && - password == other.password && - toDate == other.toDate && - casAuthority == other.casAuthority && - panNo == other.panNo && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash( - email, - fromDate, - password, - toDate, - casAuthority, - panNo, - additionalProperties, - ) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Body{email=$email, fromDate=$fromDate, password=$password, toDate=$toDate, casAuthority=$casAuthority, panNo=$panNo, additionalProperties=$additionalProperties}" - } - - /** CAS authority to generate the document from (currently only kfintech is supported) */ - class CasAuthority @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known 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. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val KFINTECH = of("kfintech") - - @JvmField val CAMS = of("cams") - - @JvmField val CDSL = of("cdsl") - - @JvmField val NSDL = of("nsdl") - - @JvmStatic fun of(value: String) = CasAuthority(JsonField.of(value)) - } - - /** An enum containing [CasAuthority]'s known values. */ - enum class Known { - KFINTECH, - CAMS, - CDSL, - NSDL, - } - - /** - * An enum containing [CasAuthority]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [CasAuthority] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. 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. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - KFINTECH, - CAMS, - CDSL, - NSDL, - /** - * An enum member indicating that [CasAuthority] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - KFINTECH -> Value.KFINTECH - CAMS -> Value.CAMS - CDSL -> Value.CDSL - NSDL -> Value.NSDL - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws CasParserInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - KFINTECH -> Known.KFINTECH - CAMS -> Known.CAMS - CDSL -> Known.CDSL - NSDL -> Known.NSDL - else -> throw CasParserInvalidDataException("Unknown CasAuthority: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws CasParserInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - CasParserInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): CasAuthority = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is CasAuthority && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is CasGeneratorGenerateCasParams && - body == other.body && - additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams - } - - override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) - - override fun toString() = - "CasGeneratorGenerateCasParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" -} diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasResponse.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasResponse.kt deleted file mode 100644 index 09df4cd..0000000 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasResponse.kt +++ /dev/null @@ -1,188 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.cas_parser.api.models.casgenerator - -import com.cas_parser.api.core.ExcludeMissing -import com.cas_parser.api.core.JsonField -import com.cas_parser.api.core.JsonMissing -import com.cas_parser.api.core.JsonValue -import com.cas_parser.api.errors.CasParserInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects -import java.util.Optional - -class CasGeneratorGenerateCasResponse -private constructor( - private val msg: JsonField, - private val status: JsonField, - private val additionalProperties: MutableMap, -) { - - @JsonCreator - private constructor( - @JsonProperty("msg") @ExcludeMissing msg: JsonField = JsonMissing.of(), - @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), - ) : this(msg, status, mutableMapOf()) - - /** - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun msg(): Optional = msg.getOptional("msg") - - /** - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun status(): Optional = status.getOptional("status") - - /** - * Returns the raw JSON value of [msg]. - * - * Unlike [msg], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("msg") @ExcludeMissing fun _msg(): JsonField = msg - - /** - * Returns the raw JSON value of [status]. - * - * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [CasGeneratorGenerateCasResponse]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [CasGeneratorGenerateCasResponse]. */ - class Builder internal constructor() { - - private var msg: JsonField = JsonMissing.of() - private var status: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(casGeneratorGenerateCasResponse: CasGeneratorGenerateCasResponse) = - apply { - msg = casGeneratorGenerateCasResponse.msg - status = casGeneratorGenerateCasResponse.status - additionalProperties = - casGeneratorGenerateCasResponse.additionalProperties.toMutableMap() - } - - fun msg(msg: String) = msg(JsonField.of(msg)) - - /** - * Sets [Builder.msg] to an arbitrary JSON value. - * - * You should usually call [Builder.msg] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun msg(msg: JsonField) = apply { this.msg = msg } - - fun status(status: String) = status(JsonField.of(status)) - - /** - * Sets [Builder.status] to an arbitrary JSON value. - * - * You should usually call [Builder.status] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun status(status: JsonField) = apply { this.status = status } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [CasGeneratorGenerateCasResponse]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): CasGeneratorGenerateCasResponse = - CasGeneratorGenerateCasResponse(msg, status, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): CasGeneratorGenerateCasResponse = apply { - if (validated) { - return@apply - } - - msg() - status() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (msg.asKnown().isPresent) 1 else 0) + (if (status.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is CasGeneratorGenerateCasResponse && - msg == other.msg && - status == other.status && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(msg, status, additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "CasGeneratorGenerateCasResponse{msg=$msg, status=$status, additionalProperties=$additionalProperties}" -} diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casparser/UnifiedResponse.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casparser/UnifiedResponse.kt index 2c18576..e64ebfb 100644 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casparser/UnifiedResponse.kt +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casparser/UnifiedResponse.kt @@ -22,12 +22,14 @@ import java.util.Optional import kotlin.jvm.optionals.getOrNull class UnifiedResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val dematAccounts: JsonField>, private val insurance: JsonField, private val investor: JsonField, private val meta: JsonField, private val mutualFunds: JsonField>, + private val nps: JsonField>, private val summary: JsonField, private val additionalProperties: MutableMap, ) { @@ -45,8 +47,9 @@ private constructor( @JsonProperty("mutual_funds") @ExcludeMissing mutualFunds: JsonField> = JsonMissing.of(), + @JsonProperty("nps") @ExcludeMissing nps: JsonField> = JsonMissing.of(), @JsonProperty("summary") @ExcludeMissing summary: JsonField = JsonMissing.of(), - ) : this(dematAccounts, insurance, investor, meta, mutualFunds, summary, mutableMapOf()) + ) : this(dematAccounts, insurance, investor, meta, mutualFunds, nps, summary, mutableMapOf()) /** * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if the @@ -78,6 +81,14 @@ private constructor( */ fun mutualFunds(): Optional> = mutualFunds.getOptional("mutual_funds") + /** + * List of NPS accounts + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun nps(): Optional> = nps.getOptional("nps") + /** * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -123,6 +134,13 @@ private constructor( @ExcludeMissing fun _mutualFunds(): JsonField> = mutualFunds + /** + * Returns the raw JSON value of [nps]. + * + * Unlike [nps], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("nps") @ExcludeMissing fun _nps(): JsonField> = nps + /** * Returns the raw JSON value of [summary]. * @@ -156,6 +174,7 @@ private constructor( private var investor: JsonField = JsonMissing.of() private var meta: JsonField = JsonMissing.of() private var mutualFunds: JsonField>? = null + private var nps: JsonField>? = null private var summary: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -166,6 +185,7 @@ private constructor( investor = unifiedResponse.investor meta = unifiedResponse.meta mutualFunds = unifiedResponse.mutualFunds.map { it.toMutableList() } + nps = unifiedResponse.nps.map { it.toMutableList() } summary = unifiedResponse.summary additionalProperties = unifiedResponse.additionalProperties.toMutableMap() } @@ -253,6 +273,26 @@ private constructor( } } + /** List of NPS accounts */ + fun nps(nps: List) = nps(JsonField.of(nps)) + + /** + * Sets [Builder.nps] to an arbitrary JSON value. + * + * You should usually call [Builder.nps] with a well-typed `List` value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun nps(nps: JsonField>) = apply { this.nps = nps.map { it.toMutableList() } } + + /** + * Adds a single [Np] to [nps]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addNp(np: Np) = apply { + nps = (nps ?: JsonField.of(mutableListOf())).also { checkKnown("nps", it).add(np) } + } + fun summary(summary: Summary) = summary(JsonField.of(summary)) /** @@ -294,6 +334,7 @@ private constructor( investor, meta, (mutualFunds ?: JsonMissing.of()).map { it.toImmutable() }, + (nps ?: JsonMissing.of()).map { it.toImmutable() }, summary, additionalProperties.toMutableMap(), ) @@ -311,6 +352,7 @@ private constructor( investor().ifPresent { it.validate() } meta().ifPresent { it.validate() } mutualFunds().ifPresent { it.forEach { it.validate() } } + nps().ifPresent { it.forEach { it.validate() } } summary().ifPresent { it.validate() } validated = true } @@ -335,9 +377,11 @@ private constructor( (investor.asKnown().getOrNull()?.validity() ?: 0) + (meta.asKnown().getOrNull()?.validity() ?: 0) + (mutualFunds.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (nps.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (summary.asKnown().getOrNull()?.validity() ?: 0) class DematAccount + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val additionalInfo: JsonField, private val boId: JsonField, @@ -346,6 +390,7 @@ private constructor( private val dpId: JsonField, private val dpName: JsonField, private val holdings: JsonField, + private val linkedHolders: JsonField>, private val value: JsonField, private val additionalProperties: MutableMap, ) { @@ -367,6 +412,9 @@ private constructor( @JsonProperty("holdings") @ExcludeMissing holdings: JsonField = JsonMissing.of(), + @JsonProperty("linked_holders") + @ExcludeMissing + linkedHolders: JsonField> = JsonMissing.of(), @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), ) : this( additionalInfo, @@ -376,6 +424,7 @@ private constructor( dpId, dpName, holdings, + linkedHolders, value, mutableMapOf(), ) @@ -435,6 +484,15 @@ private constructor( */ fun holdings(): Optional = holdings.getOptional("holdings") + /** + * List of account holders linked to this demat account + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun linkedHolders(): Optional> = + linkedHolders.getOptional("linked_holders") + /** * Total value of the demat account * @@ -497,6 +555,16 @@ private constructor( */ @JsonProperty("holdings") @ExcludeMissing fun _holdings(): JsonField = holdings + /** + * Returns the raw JSON value of [linkedHolders]. + * + * Unlike [linkedHolders], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("linked_holders") + @ExcludeMissing + fun _linkedHolders(): JsonField> = linkedHolders + /** * Returns the raw JSON value of [value]. * @@ -532,6 +600,7 @@ private constructor( private var dpId: JsonField = JsonMissing.of() private var dpName: JsonField = JsonMissing.of() private var holdings: JsonField = JsonMissing.of() + private var linkedHolders: JsonField>? = null private var value: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -544,6 +613,7 @@ private constructor( dpId = dematAccount.dpId dpName = dematAccount.dpName holdings = dematAccount.holdings + linkedHolders = dematAccount.linkedHolders.map { it.toMutableList() } value = dematAccount.value additionalProperties = dematAccount.additionalProperties.toMutableMap() } @@ -634,6 +704,33 @@ private constructor( */ fun holdings(holdings: JsonField) = apply { this.holdings = holdings } + /** List of account holders linked to this demat account */ + fun linkedHolders(linkedHolders: List) = + linkedHolders(JsonField.of(linkedHolders)) + + /** + * Sets [Builder.linkedHolders] to an arbitrary JSON value. + * + * You should usually call [Builder.linkedHolders] with a well-typed + * `List` value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun linkedHolders(linkedHolders: JsonField>) = apply { + this.linkedHolders = linkedHolders.map { it.toMutableList() } + } + + /** + * Adds a single [LinkedHolder] to [linkedHolders]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addLinkedHolder(linkedHolder: LinkedHolder) = apply { + linkedHolders = + (linkedHolders ?: JsonField.of(mutableListOf())).also { + checkKnown("linkedHolders", it).add(linkedHolder) + } + } + /** Total value of the demat account */ fun value(value: Float) = value(JsonField.of(value)) @@ -679,6 +776,7 @@ private constructor( dpId, dpName, holdings, + (linkedHolders ?: JsonMissing.of()).map { it.toImmutable() }, value, additionalProperties.toMutableMap(), ) @@ -698,6 +796,7 @@ private constructor( dpId() dpName() holdings().ifPresent { it.validate() } + linkedHolders().ifPresent { it.forEach { it.validate() } } value() validated = true } @@ -725,10 +824,12 @@ private constructor( (if (dpId.asKnown().isPresent) 1 else 0) + (if (dpName.asKnown().isPresent) 1 else 0) + (holdings.asKnown().getOrNull()?.validity() ?: 0) + + (linkedHolders.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (if (value.asKnown().isPresent) 1 else 0) /** Additional information specific to the demat account type */ class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val boStatus: JsonField, private val boSubStatus: JsonField, @@ -1310,6 +1411,7 @@ private constructor( } class Holdings + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val aifs: JsonField>, private val corporateBonds: JsonField>, @@ -1668,10 +1770,12 @@ private constructor( ?: 0) class Aif + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val additionalInfo: JsonValue, + private val additionalInfo: JsonField, private val isin: JsonField, private val name: JsonField, + private val transactions: JsonField>, private val units: JsonField, private val value: JsonField, private val additionalProperties: MutableMap, @@ -1681,25 +1785,32 @@ private constructor( private constructor( @JsonProperty("additional_info") @ExcludeMissing - additionalInfo: JsonValue = JsonMissing.of(), + additionalInfo: JsonField = JsonMissing.of(), @JsonProperty("isin") @ExcludeMissing isin: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("transactions") + @ExcludeMissing + transactions: JsonField> = JsonMissing.of(), @JsonProperty("units") @ExcludeMissing units: JsonField = JsonMissing.of(), @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), - ) : this(additionalInfo, isin, name, units, value, mutableMapOf()) + ) : this(additionalInfo, isin, name, transactions, units, value, mutableMapOf()) - /** Additional information specific to the AIF */ - @JsonProperty("additional_info") - @ExcludeMissing - fun _additionalInfo(): JsonValue = additionalInfo + /** + * Additional information specific to the AIF + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") /** * ISIN code of the AIF @@ -1717,6 +1828,15 @@ private constructor( */ fun name(): Optional = name.getOptional("name") + /** + * List of transactions for this holding (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun transactions(): Optional> = + transactions.getOptional("transactions") + /** * Number of units held * @@ -1733,6 +1853,16 @@ private constructor( */ fun value(): Optional = value.getOptional("value") + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo + /** * Returns the raw JSON value of [isin]. * @@ -1749,6 +1879,16 @@ private constructor( */ @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + /** + * Returns the raw JSON value of [transactions]. + * + * Unlike [transactions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("transactions") + @ExcludeMissing + fun _transactions(): JsonField> = transactions + /** * Returns the raw JSON value of [units]. * @@ -1786,9 +1926,10 @@ private constructor( /** A builder for [Aif]. */ class Builder internal constructor() { - private var additionalInfo: JsonValue = JsonMissing.of() + private var additionalInfo: JsonField = JsonMissing.of() private var isin: JsonField = JsonMissing.of() private var name: JsonField = JsonMissing.of() + private var transactions: JsonField>? = null private var units: JsonField = JsonMissing.of() private var value: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -1798,13 +1939,24 @@ private constructor( additionalInfo = aif.additionalInfo isin = aif.isin name = aif.name + transactions = aif.transactions.map { it.toMutableList() } units = aif.units value = aif.value additionalProperties = aif.additionalProperties.toMutableMap() } /** Additional information specific to the AIF */ - fun additionalInfo(additionalInfo: JsonValue) = apply { + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) + + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { this.additionalInfo = additionalInfo } @@ -1832,6 +1984,33 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } + /** List of transactions for this holding (beta) */ + fun transactions(transactions: List) = + transactions(JsonField.of(transactions)) + + /** + * Sets [Builder.transactions] to an arbitrary JSON value. + * + * You should usually call [Builder.transactions] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun transactions(transactions: JsonField>) = apply { + this.transactions = transactions.map { it.toMutableList() } + } + + /** + * Adds a single [Transaction] to [transactions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTransaction(transaction: Transaction) = apply { + transactions = + (transactions ?: JsonField.of(mutableListOf())).also { + checkKnown("transactions", it).add(transaction) + } + } + /** Number of units held */ fun units(units: Float) = units(JsonField.of(units)) @@ -1888,6 +2067,7 @@ private constructor( additionalInfo, isin, name, + (transactions ?: JsonMissing.of()).map { it.toImmutable() }, units, value, additionalProperties.toMutableMap(), @@ -1901,8 +2081,10 @@ private constructor( return@apply } + additionalInfo().ifPresent { it.validate() } isin() name() + transactions().ifPresent { it.forEach { it.validate() } } units() value() validated = true @@ -1924,373 +2106,1553 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (isin.asKnown().isPresent) 1 else 0) + + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (isin.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + + (transactions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (if (units.asKnown().isPresent) 1 else 0) + (if (value.asKnown().isPresent) 1 else 0) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** Additional information specific to the AIF */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val closeUnits: JsonField, + private val openUnits: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("close_units") + @ExcludeMissing + closeUnits: JsonField = JsonMissing.of(), + @JsonProperty("open_units") + @ExcludeMissing + openUnits: JsonField = JsonMissing.of(), + ) : this(closeUnits, openUnits, mutableMapOf()) - return other is Aif && - additionalInfo == other.additionalInfo && - isin == other.isin && - name == other.name && - units == other.units && - value == other.value && - additionalProperties == other.additionalProperties - } + /** + * Closing balance units for the statement period (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun closeUnits(): Optional = closeUnits.getOptional("close_units") - private val hashCode: Int by lazy { - Objects.hash(additionalInfo, isin, name, units, value, additionalProperties) - } + /** + * Opening balance units for the statement period (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun openUnits(): Optional = openUnits.getOptional("open_units") - override fun hashCode(): Int = hashCode + /** + * Returns the raw JSON value of [closeUnits]. + * + * Unlike [closeUnits], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("close_units") + @ExcludeMissing + fun _closeUnits(): JsonField = closeUnits - override fun toString() = - "Aif{additionalInfo=$additionalInfo, isin=$isin, name=$name, units=$units, value=$value, additionalProperties=$additionalProperties}" - } + /** + * Returns the raw JSON value of [openUnits]. + * + * Unlike [openUnits], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("open_units") + @ExcludeMissing + fun _openUnits(): JsonField = openUnits - class CorporateBond - private constructor( - private val additionalInfo: JsonValue, - private val isin: JsonField, - private val name: JsonField, - private val units: JsonField, - private val value: JsonField, - private val additionalProperties: MutableMap, - ) { + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - @JsonCreator - private constructor( - @JsonProperty("additional_info") - @ExcludeMissing - additionalInfo: JsonValue = JsonMissing.of(), - @JsonProperty("isin") - @ExcludeMissing - isin: JsonField = JsonMissing.of(), - @JsonProperty("name") - @ExcludeMissing - name: JsonField = JsonMissing.of(), - @JsonProperty("units") - @ExcludeMissing - units: JsonField = JsonMissing.of(), - @JsonProperty("value") + @JsonAnyGetter @ExcludeMissing - value: JsonField = JsonMissing.of(), - ) : this(additionalInfo, isin, name, units, value, mutableMapOf()) + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - /** Additional information specific to the corporate bond */ - @JsonProperty("additional_info") - @ExcludeMissing - fun _additionalInfo(): JsonValue = additionalInfo + fun toBuilder() = Builder().from(this) - /** - * ISIN code of the corporate bond - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun isin(): Optional = isin.getOptional("isin") + companion object { - /** - * Name of the corporate bond - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun name(): Optional = name.getOptional("name") + /** + * Returns a mutable builder for constructing an instance of + * [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } - /** - * Number of units held - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun units(): Optional = units.getOptional("units") + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { - /** - * Current market value of the holding - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun value(): Optional = value.getOptional("value") + private var closeUnits: JsonField = JsonMissing.of() + private var openUnits: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() - /** - * Returns the raw JSON value of [isin]. - * - * Unlike [isin], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("isin") @ExcludeMissing fun _isin(): JsonField = isin + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + closeUnits = additionalInfo.closeUnits + openUnits = additionalInfo.openUnits + additionalProperties = + additionalInfo.additionalProperties.toMutableMap() + } - /** - * Returns the raw JSON value of [name]. - * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + /** Closing balance units for the statement period (beta) */ + fun closeUnits(closeUnits: Float?) = + closeUnits(JsonField.ofNullable(closeUnits)) + + /** + * Alias for [Builder.closeUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun closeUnits(closeUnits: Float) = closeUnits(closeUnits as Float?) + + /** + * Alias for calling [Builder.closeUnits] with `closeUnits.orElse(null)`. + */ + fun closeUnits(closeUnits: Optional) = + closeUnits(closeUnits.getOrNull()) + + /** + * Sets [Builder.closeUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.closeUnits] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun closeUnits(closeUnits: JsonField) = apply { + this.closeUnits = closeUnits + } - /** - * Returns the raw JSON value of [units]. - * - * Unlike [units], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units + /** Opening balance units for the statement period (beta) */ + fun openUnits(openUnits: Float?) = + openUnits(JsonField.ofNullable(openUnits)) + + /** + * Alias for [Builder.openUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun openUnits(openUnits: Float) = openUnits(openUnits as Float?) + + /** Alias for calling [Builder.openUnits] with `openUnits.orElse(null)`. */ + fun openUnits(openUnits: Optional) = openUnits(openUnits.getOrNull()) + + /** + * Sets [Builder.openUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.openUnits] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun openUnits(openUnits: JsonField) = apply { + this.openUnits = openUnits + } - /** - * Returns the raw JSON value of [value]. - * - * Unlike [value], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } - fun toBuilder() = Builder().from(this) + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - companion object { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - /** - * Returns a mutable builder for constructing an instance of [CorporateBond]. - */ - @JvmStatic fun builder() = Builder() - } + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + closeUnits, + openUnits, + additionalProperties.toMutableMap(), + ) + } - /** A builder for [CorporateBond]. */ - class Builder internal constructor() { + private var validated: Boolean = false - private var additionalInfo: JsonValue = JsonMissing.of() - private var isin: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var units: JsonField = JsonMissing.of() - private var value: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } - @JvmSynthetic - internal fun from(corporateBond: CorporateBond) = apply { - additionalInfo = corporateBond.additionalInfo - isin = corporateBond.isin - name = corporateBond.name - units = corporateBond.units - value = corporateBond.value - additionalProperties = corporateBond.additionalProperties.toMutableMap() + closeUnits() + openUnits() + validated = true } - /** Additional information specific to the corporate bond */ - fun additionalInfo(additionalInfo: JsonValue) = apply { - this.additionalInfo = additionalInfo - } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } - /** ISIN code of the corporate bond */ - fun isin(isin: String) = isin(JsonField.of(isin)) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (closeUnits.asKnown().isPresent) 1 else 0) + + (if (openUnits.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AdditionalInfo && + closeUnits == other.closeUnits && + openUnits == other.openUnits && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(closeUnits, openUnits, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AdditionalInfo{closeUnits=$closeUnits, openUnits=$openUnits, additionalProperties=$additionalProperties}" + } + + /** + * Unified transaction schema for all holding types (MF folios, equities, bonds, + * etc.) + */ + class Transaction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, + private val amount: JsonField, + private val balance: JsonField, + private val date: JsonField, + private val description: JsonField, + private val dividendRate: JsonField, + private val nav: JsonField, + private val type: JsonField, + private val units: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("amount") + @ExcludeMissing + amount: JsonField = JsonMissing.of(), + @JsonProperty("balance") + @ExcludeMissing + balance: JsonField = JsonMissing.of(), + @JsonProperty("date") + @ExcludeMissing + date: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("dividend_rate") + @ExcludeMissing + dividendRate: JsonField = JsonMissing.of(), + @JsonProperty("nav") + @ExcludeMissing + nav: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + @JsonProperty("units") + @ExcludeMissing + units: JsonField = JsonMissing.of(), + ) : this( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + mutableMapOf(), + ) /** - * Sets [Builder.isin] to an arbitrary JSON value. + * Additional transaction-specific fields that vary by source * - * You should usually call [Builder.isin] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). */ - fun isin(isin: JsonField) = apply { this.isin = isin } + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") - /** Name of the corporate bond */ - fun name(name: String) = name(JsonField.of(name)) + /** + * Transaction amount in currency (computed from units × price/NAV) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun amount(): Optional = amount.getOptional("amount") /** - * Sets [Builder.name] to an arbitrary JSON value. + * Balance units after transaction * - * You should usually call [Builder.name] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). */ - fun name(name: JsonField) = apply { this.name = name } + fun balance(): Optional = balance.getOptional("balance") - /** Number of units held */ - fun units(units: Float) = units(JsonField.of(units)) + /** + * Transaction date (YYYY-MM-DD) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun date(): Optional = date.getOptional("date") /** - * Sets [Builder.units] to an arbitrary JSON value. + * Transaction description/particulars * - * You should usually call [Builder.units] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). */ - fun units(units: JsonField) = apply { this.units = units } + fun description(): Optional = description.getOptional("description") - /** Current market value of the holding */ - fun value(value: Float) = value(JsonField.of(value)) + /** + * Dividend rate (for DIVIDEND_PAYOUT transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun dividendRate(): Optional = dividendRate.getOptional("dividend_rate") /** - * Sets [Builder.value] to an arbitrary JSON value. + * NAV/price per unit on transaction date * - * You should usually call [Builder.value] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). */ - fun value(value: JsonField) = apply { this.value = value } + fun nav(): Optional = nav.getOptional("nav") - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, + * REVERSAL, UNKNOWN. + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") - fun putAdditionalProperty(key: String, value: JsonValue) = apply { + /** + * Number of units involved in transaction + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun units(): Optional = units.getOptional("units") + + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo + + /** + * Returns the raw JSON value of [amount]. + * + * Unlike [amount], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("amount") @ExcludeMissing fun _amount(): JsonField = amount + + /** + * Returns the raw JSON value of [balance]. + * + * Unlike [balance], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("balance") + @ExcludeMissing + fun _balance(): JsonField = balance + + /** + * Returns the raw JSON value of [date]. + * + * Unlike [date], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("date") @ExcludeMissing fun _date(): JsonField = date + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description + + /** + * Returns the raw JSON value of [dividendRate]. + * + * Unlike [dividendRate], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("dividend_rate") + @ExcludeMissing + fun _dividendRate(): JsonField = dividendRate + + /** + * Returns the raw JSON value of [nav]. + * + * Unlike [nav], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("nav") @ExcludeMissing fun _nav(): JsonField = nav + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [units]. + * + * Unlike [units], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Transaction]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Transaction]. */ + class Builder internal constructor() { + + private var additionalInfo: JsonField = JsonMissing.of() + private var amount: JsonField = JsonMissing.of() + private var balance: JsonField = JsonMissing.of() + private var date: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var dividendRate: JsonField = JsonMissing.of() + private var nav: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var units: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(transaction: Transaction) = apply { + additionalInfo = transaction.additionalInfo + amount = transaction.amount + balance = transaction.balance + date = transaction.date + description = transaction.description + dividendRate = transaction.dividendRate + nav = transaction.nav + type = transaction.type + units = transaction.units + additionalProperties = transaction.additionalProperties.toMutableMap() } - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) + /** Additional transaction-specific fields that vary by source */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) + + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { + this.additionalInfo = additionalInfo + } + + /** Transaction amount in currency (computed from units × price/NAV) */ + fun amount(amount: Float?) = amount(JsonField.ofNullable(amount)) + + /** + * Alias for [Builder.amount]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun amount(amount: Float) = amount(amount as Float?) + + /** Alias for calling [Builder.amount] with `amount.orElse(null)`. */ + fun amount(amount: Optional) = amount(amount.getOrNull()) + + /** + * Sets [Builder.amount] to an arbitrary JSON value. + * + * You should usually call [Builder.amount] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun amount(amount: JsonField) = apply { this.amount = amount } + + /** Balance units after transaction */ + fun balance(balance: Float) = balance(JsonField.of(balance)) + + /** + * Sets [Builder.balance] to an arbitrary JSON value. + * + * You should usually call [Builder.balance] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun balance(balance: JsonField) = apply { this.balance = balance } + + /** Transaction date (YYYY-MM-DD) */ + fun date(date: LocalDate) = date(JsonField.of(date)) + + /** + * Sets [Builder.date] to an arbitrary JSON value. + * + * You should usually call [Builder.date] with a well-typed [LocalDate] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun date(date: JsonField) = apply { this.date = date } + + /** Transaction description/particulars */ + fun description(description: String) = + description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } + + /** Dividend rate (for DIVIDEND_PAYOUT transactions) */ + fun dividendRate(dividendRate: Float?) = + dividendRate(JsonField.ofNullable(dividendRate)) + + /** + * Alias for [Builder.dividendRate]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun dividendRate(dividendRate: Float) = dividendRate(dividendRate as Float?) + + /** + * Alias for calling [Builder.dividendRate] with + * `dividendRate.orElse(null)`. + */ + fun dividendRate(dividendRate: Optional) = + dividendRate(dividendRate.getOrNull()) + + /** + * Sets [Builder.dividendRate] to an arbitrary JSON value. + * + * You should usually call [Builder.dividendRate] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun dividendRate(dividendRate: JsonField) = apply { + this.dividendRate = dividendRate + } + + /** NAV/price per unit on transaction date */ + fun nav(nav: Float?) = nav(JsonField.ofNullable(nav)) + + /** + * Alias for [Builder.nav]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun nav(nav: Float) = nav(nav as Float?) + + /** Alias for calling [Builder.nav] with `nav.orElse(null)`. */ + fun nav(nav: Optional) = nav(nav.getOrNull()) + + /** + * Sets [Builder.nav] to an arbitrary JSON value. + * + * You should usually call [Builder.nav] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun nav(nav: JsonField) = apply { this.nav = nav } + + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, + * DIVIDEND_PAYOUT, DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, + * STT_TAX, MISC, REVERSAL, UNKNOWN. + */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + /** Number of units involved in transaction */ + fun units(units: Float) = units(JsonField.of(units)) + + /** + * Sets [Builder.units] to an arbitrary JSON value. + * + * You should usually call [Builder.units] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun units(units: JsonField) = apply { this.units = units } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Transaction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Transaction = + Transaction( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + additionalProperties.toMutableMap(), + ) } - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) + private var validated: Boolean = false + + fun validate(): Transaction = apply { + if (validated) { + return@apply + } + + additionalInfo().ifPresent { it.validate() } + amount() + balance() + date() + description() + dividendRate() + nav() + type().ifPresent { it.validate() } + units() + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + /** - * Returns an immutable instance of [CorporateBond]. + * Returns a score indicating how many valid values are contained in this object + * recursively. * - * Further updates to this [Builder] will not mutate the returned instance. + * Used for best match union deserialization. */ - fun build(): CorporateBond = - CorporateBond( - additionalInfo, - isin, - name, - units, - value, - additionalProperties.toMutableMap(), + @JvmSynthetic + internal fun validity(): Int = + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (amount.asKnown().isPresent) 1 else 0) + + (if (balance.asKnown().isPresent) 1 else 0) + + (if (date.asKnown().isPresent) 1 else 0) + + (if (description.asKnown().isPresent) 1 else 0) + + (if (dividendRate.asKnown().isPresent) 1 else 0) + + (if (nav.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (units.asKnown().isPresent) 1 else 0) + + /** Additional transaction-specific fields that vary by source */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val capitalWithdrawal: JsonField, + private val credit: JsonField, + private val debit: JsonField, + private val incomeDistribution: JsonField, + private val orderNo: JsonField, + private val price: JsonField, + private val stampDuty: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("capital_withdrawal") + @ExcludeMissing + capitalWithdrawal: JsonField = JsonMissing.of(), + @JsonProperty("credit") + @ExcludeMissing + credit: JsonField = JsonMissing.of(), + @JsonProperty("debit") + @ExcludeMissing + debit: JsonField = JsonMissing.of(), + @JsonProperty("income_distribution") + @ExcludeMissing + incomeDistribution: JsonField = JsonMissing.of(), + @JsonProperty("order_no") + @ExcludeMissing + orderNo: JsonField = JsonMissing.of(), + @JsonProperty("price") + @ExcludeMissing + price: JsonField = JsonMissing.of(), + @JsonProperty("stamp_duty") + @ExcludeMissing + stampDuty: JsonField = JsonMissing.of(), + ) : this( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + mutableMapOf(), ) - } - private var validated: Boolean = false + /** + * Capital withdrawal amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun capitalWithdrawal(): Optional = + capitalWithdrawal.getOptional("capital_withdrawal") + + /** + * Units credited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun credit(): Optional = credit.getOptional("credit") + + /** + * Units debited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun debit(): Optional = debit.getOptional("debit") + + /** + * Income distribution amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun incomeDistribution(): Optional = + incomeDistribution.getOptional("income_distribution") + + /** + * Order/transaction reference number (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun orderNo(): Optional = orderNo.getOptional("order_no") + + /** + * Price per unit (NSDL/CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun price(): Optional = price.getOptional("price") + + /** + * Stamp duty charged + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun stampDuty(): Optional = stampDuty.getOptional("stamp_duty") + + /** + * Returns the raw JSON value of [capitalWithdrawal]. + * + * Unlike [capitalWithdrawal], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("capital_withdrawal") + @ExcludeMissing + fun _capitalWithdrawal(): JsonField = capitalWithdrawal + + /** + * Returns the raw JSON value of [credit]. + * + * Unlike [credit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("credit") + @ExcludeMissing + fun _credit(): JsonField = credit + + /** + * Returns the raw JSON value of [debit]. + * + * Unlike [debit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("debit") + @ExcludeMissing + fun _debit(): JsonField = debit + + /** + * Returns the raw JSON value of [incomeDistribution]. + * + * Unlike [incomeDistribution], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("income_distribution") + @ExcludeMissing + fun _incomeDistribution(): JsonField = incomeDistribution + + /** + * Returns the raw JSON value of [orderNo]. + * + * Unlike [orderNo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("order_no") + @ExcludeMissing + fun _orderNo(): JsonField = orderNo + + /** + * Returns the raw JSON value of [price]. + * + * Unlike [price], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("price") + @ExcludeMissing + fun _price(): JsonField = price + + /** + * Returns the raw JSON value of [stampDuty]. + * + * Unlike [stampDuty], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("stamp_duty") + @ExcludeMissing + fun _stampDuty(): JsonField = stampDuty + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - fun validate(): CorporateBond = apply { - if (validated) { - return@apply - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - isin() - name() - units() - value() - validated = true - } + fun toBuilder() = Builder().from(this) - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + companion object { - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (isin.asKnown().isPresent) 1 else 0) + - (if (name.asKnown().isPresent) 1 else 0) + - (if (units.asKnown().isPresent) 1 else 0) + - (if (value.asKnown().isPresent) 1 else 0) + /** + * Returns a mutable builder for constructing an instance of + * [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { + + private var capitalWithdrawal: JsonField = JsonMissing.of() + private var credit: JsonField = JsonMissing.of() + private var debit: JsonField = JsonMissing.of() + private var incomeDistribution: JsonField = JsonMissing.of() + private var orderNo: JsonField = JsonMissing.of() + private var price: JsonField = JsonMissing.of() + private var stampDuty: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + capitalWithdrawal = additionalInfo.capitalWithdrawal + credit = additionalInfo.credit + debit = additionalInfo.debit + incomeDistribution = additionalInfo.incomeDistribution + orderNo = additionalInfo.orderNo + price = additionalInfo.price + stampDuty = additionalInfo.stampDuty + additionalProperties = + additionalInfo.additionalProperties.toMutableMap() + } + + /** Capital withdrawal amount (CDSL MF transactions) */ + fun capitalWithdrawal(capitalWithdrawal: Float) = + capitalWithdrawal(JsonField.of(capitalWithdrawal)) + + /** + * Sets [Builder.capitalWithdrawal] to an arbitrary JSON value. + * + * You should usually call [Builder.capitalWithdrawal] with a well-typed + * [Float] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun capitalWithdrawal(capitalWithdrawal: JsonField) = apply { + this.capitalWithdrawal = capitalWithdrawal + } + + /** Units credited (demat transactions) */ + fun credit(credit: Float) = credit(JsonField.of(credit)) + + /** + * Sets [Builder.credit] to an arbitrary JSON value. + * + * You should usually call [Builder.credit] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun credit(credit: JsonField) = apply { this.credit = credit } + + /** Units debited (demat transactions) */ + fun debit(debit: Float) = debit(JsonField.of(debit)) + + /** + * Sets [Builder.debit] to an arbitrary JSON value. + * + * You should usually call [Builder.debit] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun debit(debit: JsonField) = apply { this.debit = debit } + + /** Income distribution amount (CDSL MF transactions) */ + fun incomeDistribution(incomeDistribution: Float) = + incomeDistribution(JsonField.of(incomeDistribution)) + + /** + * Sets [Builder.incomeDistribution] to an arbitrary JSON value. + * + * You should usually call [Builder.incomeDistribution] with a + * well-typed [Float] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun incomeDistribution(incomeDistribution: JsonField) = apply { + this.incomeDistribution = incomeDistribution + } + + /** Order/transaction reference number (demat transactions) */ + fun orderNo(orderNo: String) = orderNo(JsonField.of(orderNo)) + + /** + * Sets [Builder.orderNo] to an arbitrary JSON value. + * + * You should usually call [Builder.orderNo] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun orderNo(orderNo: JsonField) = apply { + this.orderNo = orderNo + } + + /** Price per unit (NSDL/CDSL MF transactions) */ + fun price(price: Float) = price(JsonField.of(price)) + + /** + * Sets [Builder.price] to an arbitrary JSON value. + * + * You should usually call [Builder.price] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun price(price: JsonField) = apply { this.price = price } + + /** Stamp duty charged */ + fun stampDuty(stampDuty: Float) = stampDuty(JsonField.of(stampDuty)) + + /** + * Sets [Builder.stampDuty] to an arbitrary JSON value. + * + * You should usually call [Builder.stampDuty] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun stampDuty(stampDuty: JsonField) = apply { + this.stampDuty = stampDuty + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } + + capitalWithdrawal() + credit() + debit() + incomeDistribution() + orderNo() + price() + stampDuty() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (capitalWithdrawal.asKnown().isPresent) 1 else 0) + + (if (credit.asKnown().isPresent) 1 else 0) + + (if (debit.asKnown().isPresent) 1 else 0) + + (if (incomeDistribution.asKnown().isPresent) 1 else 0) + + (if (orderNo.asKnown().isPresent) 1 else 0) + + (if (price.asKnown().isPresent) 1 else 0) + + (if (stampDuty.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AdditionalInfo && + capitalWithdrawal == other.capitalWithdrawal && + credit == other.credit && + debit == other.debit && + incomeDistribution == other.incomeDistribution && + orderNo == other.orderNo && + price == other.price && + stampDuty == other.stampDuty && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AdditionalInfo{capitalWithdrawal=$capitalWithdrawal, credit=$credit, debit=$debit, incomeDistribution=$incomeDistribution, orderNo=$orderNo, price=$price, stampDuty=$stampDuty, additionalProperties=$additionalProperties}" } - return other is CorporateBond && - additionalInfo == other.additionalInfo && - isin == other.isin && - name == other.name && - units == other.units && - value == other.value && - additionalProperties == other.additionalProperties - } + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, + * REVERSAL, UNKNOWN. + */ + class Type + @JsonCreator + private constructor(private val value: JsonField) : Enum { - private val hashCode: Int by lazy { - Objects.hash(additionalInfo, isin, name, units, value, additionalProperties) - } + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data + * that doesn't match any known 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. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value - override fun hashCode(): Int = hashCode + companion object { - override fun toString() = - "CorporateBond{additionalInfo=$additionalInfo, isin=$isin, name=$name, units=$units, value=$value, additionalProperties=$additionalProperties}" - } + @JvmField val PURCHASE = of("PURCHASE") - class DematMutualFund - private constructor( - private val additionalInfo: JsonValue, - private val isin: JsonField, - private val name: JsonField, - private val units: JsonField, - private val value: JsonField, - private val additionalProperties: MutableMap, - ) { + @JvmField val PURCHASE_SIP = of("PURCHASE_SIP") - @JsonCreator - private constructor( - @JsonProperty("additional_info") - @ExcludeMissing - additionalInfo: JsonValue = JsonMissing.of(), - @JsonProperty("isin") - @ExcludeMissing - isin: JsonField = JsonMissing.of(), - @JsonProperty("name") - @ExcludeMissing - name: JsonField = JsonMissing.of(), - @JsonProperty("units") - @ExcludeMissing - units: JsonField = JsonMissing.of(), - @JsonProperty("value") - @ExcludeMissing - value: JsonField = JsonMissing.of(), - ) : this(additionalInfo, isin, name, units, value, mutableMapOf()) + @JvmField val REDEMPTION = of("REDEMPTION") - /** Additional information specific to the mutual fund */ - @JsonProperty("additional_info") - @ExcludeMissing - fun _additionalInfo(): JsonValue = additionalInfo + @JvmField val SWITCH_IN = of("SWITCH_IN") - /** - * ISIN code of the mutual fund - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun isin(): Optional = isin.getOptional("isin") + @JvmField val SWITCH_IN_MERGER = of("SWITCH_IN_MERGER") + + @JvmField val SWITCH_OUT = of("SWITCH_OUT") + + @JvmField val SWITCH_OUT_MERGER = of("SWITCH_OUT_MERGER") + + @JvmField val DIVIDEND_PAYOUT = of("DIVIDEND_PAYOUT") + + @JvmField val DIVIDEND_REINVEST = of("DIVIDEND_REINVEST") + + @JvmField val SEGREGATION = of("SEGREGATION") + + @JvmField val STAMP_DUTY_TAX = of("STAMP_DUTY_TAX") + + @JvmField val TDS_TAX = of("TDS_TAX") + + @JvmField val STT_TAX = of("STT_TAX") + + @JvmField val MISC = of("MISC") + + @JvmField val REVERSAL = of("REVERSAL") + + @JvmField val UNKNOWN = of("UNKNOWN") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. 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. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + /** + * An enum member indicating that [Type] was instantiated with an + * unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always + * known or if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + PURCHASE -> Value.PURCHASE + PURCHASE_SIP -> Value.PURCHASE_SIP + REDEMPTION -> Value.REDEMPTION + SWITCH_IN -> Value.SWITCH_IN + SWITCH_IN_MERGER -> Value.SWITCH_IN_MERGER + SWITCH_OUT -> Value.SWITCH_OUT + SWITCH_OUT_MERGER -> Value.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Value.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Value.DIVIDEND_REINVEST + SEGREGATION -> Value.SEGREGATION + STAMP_DUTY_TAX -> Value.STAMP_DUTY_TAX + TDS_TAX -> Value.TDS_TAX + STT_TAX -> Value.STT_TAX + MISC -> Value.MISC + REVERSAL -> Value.REVERSAL + UNKNOWN -> Value.UNKNOWN + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always + * known and don't want to throw for the unknown case. + * + * @throws CasParserInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + PURCHASE -> Known.PURCHASE + PURCHASE_SIP -> Known.PURCHASE_SIP + REDEMPTION -> Known.REDEMPTION + SWITCH_IN -> Known.SWITCH_IN + SWITCH_IN_MERGER -> Known.SWITCH_IN_MERGER + SWITCH_OUT -> Known.SWITCH_OUT + SWITCH_OUT_MERGER -> Known.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Known.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Known.DIVIDEND_REINVEST + SEGREGATION -> Known.SEGREGATION + STAMP_DUTY_TAX -> Known.STAMP_DUTY_TAX + TDS_TAX -> Known.TDS_TAX + STT_TAX -> Known.STT_TAX + MISC -> Known.MISC + REVERSAL -> Known.REVERSAL + UNKNOWN -> Known.UNKNOWN + else -> throw CasParserInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily + * for debugging and generally doesn't throw. + * + * @throws CasParserInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + CasParserInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Transaction && + additionalInfo == other.additionalInfo && + amount == other.amount && + balance == other.balance && + date == other.date && + description == other.description && + dividendRate == other.dividendRate && + nav == other.nav && + type == other.type && + units == other.units && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Transaction{additionalInfo=$additionalInfo, amount=$amount, balance=$balance, date=$date, description=$description, dividendRate=$dividendRate, nav=$nav, type=$type, units=$units, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Aif && + additionalInfo == other.additionalInfo && + isin == other.isin && + name == other.name && + transactions == other.transactions && + units == other.units && + value == other.value && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + isin, + name, + transactions, + units, + value, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Aif{additionalInfo=$additionalInfo, isin=$isin, name=$name, transactions=$transactions, units=$units, value=$value, additionalProperties=$additionalProperties}" + } + + class CorporateBond + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, + private val isin: JsonField, + private val name: JsonField, + private val transactions: JsonField>, + private val units: JsonField, + private val value: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("isin") + @ExcludeMissing + isin: JsonField = JsonMissing.of(), + @JsonProperty("name") + @ExcludeMissing + name: JsonField = JsonMissing.of(), + @JsonProperty("transactions") + @ExcludeMissing + transactions: JsonField> = JsonMissing.of(), + @JsonProperty("units") + @ExcludeMissing + units: JsonField = JsonMissing.of(), + @JsonProperty("value") + @ExcludeMissing + value: JsonField = JsonMissing.of(), + ) : this(additionalInfo, isin, name, transactions, units, value, mutableMapOf()) /** - * Name of the mutual fund + * Additional information specific to the corporate bond + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") + + /** + * ISIN code of the corporate bond + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun isin(): Optional = isin.getOptional("isin") + + /** + * Name of the corporate bond * * @throws CasParserInvalidDataException if the JSON field has an unexpected type * (e.g. if the server responded with an unexpected value). */ fun name(): Optional = name.getOptional("name") + /** + * List of transactions for this holding (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun transactions(): Optional> = + transactions.getOptional("transactions") + /** * Number of units held * @@ -2307,6 +3669,16 @@ private constructor( */ fun value(): Optional = value.getOptional("value") + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo + /** * Returns the raw JSON value of [isin]. * @@ -2323,6 +3695,16 @@ private constructor( */ @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + /** + * Returns the raw JSON value of [transactions]. + * + * Unlike [transactions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("transactions") + @ExcludeMissing + fun _transactions(): JsonField> = transactions + /** * Returns the raw JSON value of [units]. * @@ -2354,37 +3736,49 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [DematMutualFund]. + * Returns a mutable builder for constructing an instance of [CorporateBond]. */ @JvmStatic fun builder() = Builder() } - /** A builder for [DematMutualFund]. */ + /** A builder for [CorporateBond]. */ class Builder internal constructor() { - private var additionalInfo: JsonValue = JsonMissing.of() + private var additionalInfo: JsonField = JsonMissing.of() private var isin: JsonField = JsonMissing.of() private var name: JsonField = JsonMissing.of() + private var transactions: JsonField>? = null private var units: JsonField = JsonMissing.of() private var value: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(dematMutualFund: DematMutualFund) = apply { - additionalInfo = dematMutualFund.additionalInfo - isin = dematMutualFund.isin - name = dematMutualFund.name - units = dematMutualFund.units - value = dematMutualFund.value - additionalProperties = dematMutualFund.additionalProperties.toMutableMap() + internal fun from(corporateBond: CorporateBond) = apply { + additionalInfo = corporateBond.additionalInfo + isin = corporateBond.isin + name = corporateBond.name + transactions = corporateBond.transactions.map { it.toMutableList() } + units = corporateBond.units + value = corporateBond.value + additionalProperties = corporateBond.additionalProperties.toMutableMap() } - /** Additional information specific to the mutual fund */ - fun additionalInfo(additionalInfo: JsonValue) = apply { + /** Additional information specific to the corporate bond */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) + + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { this.additionalInfo = additionalInfo } - /** ISIN code of the mutual fund */ + /** ISIN code of the corporate bond */ fun isin(isin: String) = isin(JsonField.of(isin)) /** @@ -2396,7 +3790,7 @@ private constructor( */ fun isin(isin: JsonField) = apply { this.isin = isin } - /** Name of the mutual fund */ + /** Name of the corporate bond */ fun name(name: String) = name(JsonField.of(name)) /** @@ -2408,6 +3802,33 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } + /** List of transactions for this holding (beta) */ + fun transactions(transactions: List) = + transactions(JsonField.of(transactions)) + + /** + * Sets [Builder.transactions] to an arbitrary JSON value. + * + * You should usually call [Builder.transactions] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun transactions(transactions: JsonField>) = apply { + this.transactions = transactions.map { it.toMutableList() } + } + + /** + * Adds a single [Transaction] to [transactions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTransaction(transaction: Transaction) = apply { + transactions = + (transactions ?: JsonField.of(mutableListOf())).also { + checkKnown("transactions", it).add(transaction) + } + } + /** Number of units held */ fun units(units: Float) = units(JsonField.of(units)) @@ -2455,15 +3876,16 @@ private constructor( } /** - * Returns an immutable instance of [DematMutualFund]. + * Returns an immutable instance of [CorporateBond]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): DematMutualFund = - DematMutualFund( + fun build(): CorporateBond = + CorporateBond( additionalInfo, isin, name, + (transactions ?: JsonMissing.of()).map { it.toImmutable() }, units, value, additionalProperties.toMutableMap(), @@ -2472,13 +3894,15 @@ private constructor( private var validated: Boolean = false - fun validate(): DematMutualFund = apply { + fun validate(): CorporateBond = apply { if (validated) { return@apply } + additionalInfo().ifPresent { it.validate() } isin() name() + transactions().ifPresent { it.forEach { it.validate() } } units() value() validated = true @@ -2500,326 +3924,1492 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (isin.asKnown().isPresent) 1 else 0) + + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (isin.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + + (transactions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (if (units.asKnown().isPresent) 1 else 0) + (if (value.asKnown().isPresent) 1 else 0) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** Additional information specific to the corporate bond */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val closeUnits: JsonField, + private val openUnits: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("close_units") + @ExcludeMissing + closeUnits: JsonField = JsonMissing.of(), + @JsonProperty("open_units") + @ExcludeMissing + openUnits: JsonField = JsonMissing.of(), + ) : this(closeUnits, openUnits, mutableMapOf()) - return other is DematMutualFund && - additionalInfo == other.additionalInfo && - isin == other.isin && - name == other.name && - units == other.units && - value == other.value && - additionalProperties == other.additionalProperties - } + /** + * Closing balance units for the statement period (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun closeUnits(): Optional = closeUnits.getOptional("close_units") - private val hashCode: Int by lazy { - Objects.hash(additionalInfo, isin, name, units, value, additionalProperties) - } + /** + * Opening balance units for the statement period (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun openUnits(): Optional = openUnits.getOptional("open_units") - override fun hashCode(): Int = hashCode + /** + * Returns the raw JSON value of [closeUnits]. + * + * Unlike [closeUnits], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("close_units") + @ExcludeMissing + fun _closeUnits(): JsonField = closeUnits - override fun toString() = - "DematMutualFund{additionalInfo=$additionalInfo, isin=$isin, name=$name, units=$units, value=$value, additionalProperties=$additionalProperties}" - } + /** + * Returns the raw JSON value of [openUnits]. + * + * Unlike [openUnits], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("open_units") + @ExcludeMissing + fun _openUnits(): JsonField = openUnits - class Equity - private constructor( - private val additionalInfo: JsonValue, - private val isin: JsonField, - private val name: JsonField, - private val units: JsonField, - private val value: JsonField, - private val additionalProperties: MutableMap, - ) { + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - @JsonCreator - private constructor( - @JsonProperty("additional_info") - @ExcludeMissing - additionalInfo: JsonValue = JsonMissing.of(), - @JsonProperty("isin") - @ExcludeMissing - isin: JsonField = JsonMissing.of(), - @JsonProperty("name") - @ExcludeMissing - name: JsonField = JsonMissing.of(), - @JsonProperty("units") + @JsonAnyGetter @ExcludeMissing - units: JsonField = JsonMissing.of(), - @JsonProperty("value") - @ExcludeMissing - value: JsonField = JsonMissing.of(), - ) : this(additionalInfo, isin, name, units, value, mutableMapOf()) + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - /** Additional information specific to the equity */ - @JsonProperty("additional_info") - @ExcludeMissing - fun _additionalInfo(): JsonValue = additionalInfo + fun toBuilder() = Builder().from(this) - /** - * ISIN code of the equity - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun isin(): Optional = isin.getOptional("isin") + companion object { - /** - * Name of the equity - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun name(): Optional = name.getOptional("name") + /** + * Returns a mutable builder for constructing an instance of + * [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } - /** - * Number of units held - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun units(): Optional = units.getOptional("units") + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { - /** - * Current market value of the holding - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun value(): Optional = value.getOptional("value") + private var closeUnits: JsonField = JsonMissing.of() + private var openUnits: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() - /** - * Returns the raw JSON value of [isin]. - * - * Unlike [isin], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("isin") @ExcludeMissing fun _isin(): JsonField = isin + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + closeUnits = additionalInfo.closeUnits + openUnits = additionalInfo.openUnits + additionalProperties = + additionalInfo.additionalProperties.toMutableMap() + } - /** - * Returns the raw JSON value of [name]. - * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + /** Closing balance units for the statement period (beta) */ + fun closeUnits(closeUnits: Float?) = + closeUnits(JsonField.ofNullable(closeUnits)) + + /** + * Alias for [Builder.closeUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun closeUnits(closeUnits: Float) = closeUnits(closeUnits as Float?) + + /** + * Alias for calling [Builder.closeUnits] with `closeUnits.orElse(null)`. + */ + fun closeUnits(closeUnits: Optional) = + closeUnits(closeUnits.getOrNull()) + + /** + * Sets [Builder.closeUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.closeUnits] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun closeUnits(closeUnits: JsonField) = apply { + this.closeUnits = closeUnits + } - /** - * Returns the raw JSON value of [units]. - * - * Unlike [units], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units + /** Opening balance units for the statement period (beta) */ + fun openUnits(openUnits: Float?) = + openUnits(JsonField.ofNullable(openUnits)) + + /** + * Alias for [Builder.openUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun openUnits(openUnits: Float) = openUnits(openUnits as Float?) + + /** Alias for calling [Builder.openUnits] with `openUnits.orElse(null)`. */ + fun openUnits(openUnits: Optional) = openUnits(openUnits.getOrNull()) + + /** + * Sets [Builder.openUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.openUnits] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun openUnits(openUnits: JsonField) = apply { + this.openUnits = openUnits + } - /** - * Returns the raw JSON value of [value]. - * - * Unlike [value], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } - fun toBuilder() = Builder().from(this) + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - companion object { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - /** Returns a mutable builder for constructing an instance of [Equity]. */ - @JvmStatic fun builder() = Builder() - } + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + closeUnits, + openUnits, + additionalProperties.toMutableMap(), + ) + } - /** A builder for [Equity]. */ - class Builder internal constructor() { + private var validated: Boolean = false - private var additionalInfo: JsonValue = JsonMissing.of() - private var isin: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var units: JsonField = JsonMissing.of() - private var value: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } + + closeUnits() + openUnits() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ @JvmSynthetic - internal fun from(equity: Equity) = apply { - additionalInfo = equity.additionalInfo - isin = equity.isin - name = equity.name - units = equity.units - value = equity.value - additionalProperties = equity.additionalProperties.toMutableMap() + internal fun validity(): Int = + (if (closeUnits.asKnown().isPresent) 1 else 0) + + (if (openUnits.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AdditionalInfo && + closeUnits == other.closeUnits && + openUnits == other.openUnits && + additionalProperties == other.additionalProperties } - /** Additional information specific to the equity */ - fun additionalInfo(additionalInfo: JsonValue) = apply { - this.additionalInfo = additionalInfo + private val hashCode: Int by lazy { + Objects.hash(closeUnits, openUnits, additionalProperties) } - /** ISIN code of the equity */ - fun isin(isin: String) = isin(JsonField.of(isin)) + override fun hashCode(): Int = hashCode + + override fun toString() = + "AdditionalInfo{closeUnits=$closeUnits, openUnits=$openUnits, additionalProperties=$additionalProperties}" + } + + /** + * Unified transaction schema for all holding types (MF folios, equities, bonds, + * etc.) + */ + class Transaction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, + private val amount: JsonField, + private val balance: JsonField, + private val date: JsonField, + private val description: JsonField, + private val dividendRate: JsonField, + private val nav: JsonField, + private val type: JsonField, + private val units: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("amount") + @ExcludeMissing + amount: JsonField = JsonMissing.of(), + @JsonProperty("balance") + @ExcludeMissing + balance: JsonField = JsonMissing.of(), + @JsonProperty("date") + @ExcludeMissing + date: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("dividend_rate") + @ExcludeMissing + dividendRate: JsonField = JsonMissing.of(), + @JsonProperty("nav") + @ExcludeMissing + nav: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + @JsonProperty("units") + @ExcludeMissing + units: JsonField = JsonMissing.of(), + ) : this( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + mutableMapOf(), + ) /** - * Sets [Builder.isin] to an arbitrary JSON value. + * Additional transaction-specific fields that vary by source * - * You should usually call [Builder.isin] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). */ - fun isin(isin: JsonField) = apply { this.isin = isin } + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") - /** Name of the equity */ - fun name(name: String) = name(JsonField.of(name)) + /** + * Transaction amount in currency (computed from units × price/NAV) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun amount(): Optional = amount.getOptional("amount") /** - * Sets [Builder.name] to an arbitrary JSON value. + * Balance units after transaction * - * You should usually call [Builder.name] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). */ - fun name(name: JsonField) = apply { this.name = name } + fun balance(): Optional = balance.getOptional("balance") - /** Number of units held */ - fun units(units: Float) = units(JsonField.of(units)) + /** + * Transaction date (YYYY-MM-DD) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun date(): Optional = date.getOptional("date") /** - * Sets [Builder.units] to an arbitrary JSON value. + * Transaction description/particulars * - * You should usually call [Builder.units] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). */ - fun units(units: JsonField) = apply { this.units = units } + fun description(): Optional = description.getOptional("description") - /** Current market value of the holding */ - fun value(value: Float) = value(JsonField.of(value)) + /** + * Dividend rate (for DIVIDEND_PAYOUT transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun dividendRate(): Optional = dividendRate.getOptional("dividend_rate") /** - * Sets [Builder.value] to an arbitrary JSON value. + * NAV/price per unit on transaction date * - * You should usually call [Builder.value] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). */ - fun value(value: JsonField) = apply { this.value = value } + fun nav(): Optional = nav.getOptional("nav") - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, + * REVERSAL, UNKNOWN. + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + /** + * Number of units involved in transaction + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun units(): Optional = units.getOptional("units") - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } + /** + * Returns the raw JSON value of [amount]. + * + * Unlike [amount], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("amount") @ExcludeMissing fun _amount(): JsonField = amount - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + /** + * Returns the raw JSON value of [balance]. + * + * Unlike [balance], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("balance") + @ExcludeMissing + fun _balance(): JsonField = balance /** - * Returns an immutable instance of [Equity]. + * Returns the raw JSON value of [date]. * - * Further updates to this [Builder] will not mutate the returned instance. + * Unlike [date], this method doesn't throw if the JSON field has an unexpected + * type. */ - fun build(): Equity = - Equity( - additionalInfo, - isin, - name, - units, - value, - additionalProperties.toMutableMap(), - ) - } + @JsonProperty("date") @ExcludeMissing fun _date(): JsonField = date - private var validated: Boolean = false + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description - fun validate(): Equity = apply { - if (validated) { - return@apply - } + /** + * Returns the raw JSON value of [dividendRate]. + * + * Unlike [dividendRate], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("dividend_rate") + @ExcludeMissing + fun _dividendRate(): JsonField = dividendRate - isin() - name() - units() - value() - validated = true - } + /** + * Returns the raw JSON value of [nav]. + * + * Unlike [nav], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("nav") @ExcludeMissing fun _nav(): JsonField = nav - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [units]. + * + * Unlike [units], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (isin.asKnown().isPresent) 1 else 0) + - (if (name.asKnown().isPresent) 1 else 0) + - (if (units.asKnown().isPresent) 1 else 0) + - (if (value.asKnown().isPresent) 1 else 0) + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Transaction]. + */ + @JvmStatic fun builder() = Builder() } - return other is Equity && - additionalInfo == other.additionalInfo && + /** A builder for [Transaction]. */ + class Builder internal constructor() { + + private var additionalInfo: JsonField = JsonMissing.of() + private var amount: JsonField = JsonMissing.of() + private var balance: JsonField = JsonMissing.of() + private var date: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var dividendRate: JsonField = JsonMissing.of() + private var nav: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var units: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(transaction: Transaction) = apply { + additionalInfo = transaction.additionalInfo + amount = transaction.amount + balance = transaction.balance + date = transaction.date + description = transaction.description + dividendRate = transaction.dividendRate + nav = transaction.nav + type = transaction.type + units = transaction.units + additionalProperties = transaction.additionalProperties.toMutableMap() + } + + /** Additional transaction-specific fields that vary by source */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) + + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { + this.additionalInfo = additionalInfo + } + + /** Transaction amount in currency (computed from units × price/NAV) */ + fun amount(amount: Float?) = amount(JsonField.ofNullable(amount)) + + /** + * Alias for [Builder.amount]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun amount(amount: Float) = amount(amount as Float?) + + /** Alias for calling [Builder.amount] with `amount.orElse(null)`. */ + fun amount(amount: Optional) = amount(amount.getOrNull()) + + /** + * Sets [Builder.amount] to an arbitrary JSON value. + * + * You should usually call [Builder.amount] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun amount(amount: JsonField) = apply { this.amount = amount } + + /** Balance units after transaction */ + fun balance(balance: Float) = balance(JsonField.of(balance)) + + /** + * Sets [Builder.balance] to an arbitrary JSON value. + * + * You should usually call [Builder.balance] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun balance(balance: JsonField) = apply { this.balance = balance } + + /** Transaction date (YYYY-MM-DD) */ + fun date(date: LocalDate) = date(JsonField.of(date)) + + /** + * Sets [Builder.date] to an arbitrary JSON value. + * + * You should usually call [Builder.date] with a well-typed [LocalDate] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun date(date: JsonField) = apply { this.date = date } + + /** Transaction description/particulars */ + fun description(description: String) = + description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } + + /** Dividend rate (for DIVIDEND_PAYOUT transactions) */ + fun dividendRate(dividendRate: Float?) = + dividendRate(JsonField.ofNullable(dividendRate)) + + /** + * Alias for [Builder.dividendRate]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun dividendRate(dividendRate: Float) = dividendRate(dividendRate as Float?) + + /** + * Alias for calling [Builder.dividendRate] with + * `dividendRate.orElse(null)`. + */ + fun dividendRate(dividendRate: Optional) = + dividendRate(dividendRate.getOrNull()) + + /** + * Sets [Builder.dividendRate] to an arbitrary JSON value. + * + * You should usually call [Builder.dividendRate] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun dividendRate(dividendRate: JsonField) = apply { + this.dividendRate = dividendRate + } + + /** NAV/price per unit on transaction date */ + fun nav(nav: Float?) = nav(JsonField.ofNullable(nav)) + + /** + * Alias for [Builder.nav]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun nav(nav: Float) = nav(nav as Float?) + + /** Alias for calling [Builder.nav] with `nav.orElse(null)`. */ + fun nav(nav: Optional) = nav(nav.getOrNull()) + + /** + * Sets [Builder.nav] to an arbitrary JSON value. + * + * You should usually call [Builder.nav] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun nav(nav: JsonField) = apply { this.nav = nav } + + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, + * DIVIDEND_PAYOUT, DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, + * STT_TAX, MISC, REVERSAL, UNKNOWN. + */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + /** Number of units involved in transaction */ + fun units(units: Float) = units(JsonField.of(units)) + + /** + * Sets [Builder.units] to an arbitrary JSON value. + * + * You should usually call [Builder.units] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun units(units: JsonField) = apply { this.units = units } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Transaction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Transaction = + Transaction( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Transaction = apply { + if (validated) { + return@apply + } + + additionalInfo().ifPresent { it.validate() } + amount() + balance() + date() + description() + dividendRate() + nav() + type().ifPresent { it.validate() } + units() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (amount.asKnown().isPresent) 1 else 0) + + (if (balance.asKnown().isPresent) 1 else 0) + + (if (date.asKnown().isPresent) 1 else 0) + + (if (description.asKnown().isPresent) 1 else 0) + + (if (dividendRate.asKnown().isPresent) 1 else 0) + + (if (nav.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (units.asKnown().isPresent) 1 else 0) + + /** Additional transaction-specific fields that vary by source */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val capitalWithdrawal: JsonField, + private val credit: JsonField, + private val debit: JsonField, + private val incomeDistribution: JsonField, + private val orderNo: JsonField, + private val price: JsonField, + private val stampDuty: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("capital_withdrawal") + @ExcludeMissing + capitalWithdrawal: JsonField = JsonMissing.of(), + @JsonProperty("credit") + @ExcludeMissing + credit: JsonField = JsonMissing.of(), + @JsonProperty("debit") + @ExcludeMissing + debit: JsonField = JsonMissing.of(), + @JsonProperty("income_distribution") + @ExcludeMissing + incomeDistribution: JsonField = JsonMissing.of(), + @JsonProperty("order_no") + @ExcludeMissing + orderNo: JsonField = JsonMissing.of(), + @JsonProperty("price") + @ExcludeMissing + price: JsonField = JsonMissing.of(), + @JsonProperty("stamp_duty") + @ExcludeMissing + stampDuty: JsonField = JsonMissing.of(), + ) : this( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + mutableMapOf(), + ) + + /** + * Capital withdrawal amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun capitalWithdrawal(): Optional = + capitalWithdrawal.getOptional("capital_withdrawal") + + /** + * Units credited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun credit(): Optional = credit.getOptional("credit") + + /** + * Units debited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun debit(): Optional = debit.getOptional("debit") + + /** + * Income distribution amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun incomeDistribution(): Optional = + incomeDistribution.getOptional("income_distribution") + + /** + * Order/transaction reference number (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun orderNo(): Optional = orderNo.getOptional("order_no") + + /** + * Price per unit (NSDL/CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun price(): Optional = price.getOptional("price") + + /** + * Stamp duty charged + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun stampDuty(): Optional = stampDuty.getOptional("stamp_duty") + + /** + * Returns the raw JSON value of [capitalWithdrawal]. + * + * Unlike [capitalWithdrawal], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("capital_withdrawal") + @ExcludeMissing + fun _capitalWithdrawal(): JsonField = capitalWithdrawal + + /** + * Returns the raw JSON value of [credit]. + * + * Unlike [credit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("credit") + @ExcludeMissing + fun _credit(): JsonField = credit + + /** + * Returns the raw JSON value of [debit]. + * + * Unlike [debit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("debit") + @ExcludeMissing + fun _debit(): JsonField = debit + + /** + * Returns the raw JSON value of [incomeDistribution]. + * + * Unlike [incomeDistribution], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("income_distribution") + @ExcludeMissing + fun _incomeDistribution(): JsonField = incomeDistribution + + /** + * Returns the raw JSON value of [orderNo]. + * + * Unlike [orderNo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("order_no") + @ExcludeMissing + fun _orderNo(): JsonField = orderNo + + /** + * Returns the raw JSON value of [price]. + * + * Unlike [price], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("price") + @ExcludeMissing + fun _price(): JsonField = price + + /** + * Returns the raw JSON value of [stampDuty]. + * + * Unlike [stampDuty], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("stamp_duty") + @ExcludeMissing + fun _stampDuty(): JsonField = stampDuty + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { + + private var capitalWithdrawal: JsonField = JsonMissing.of() + private var credit: JsonField = JsonMissing.of() + private var debit: JsonField = JsonMissing.of() + private var incomeDistribution: JsonField = JsonMissing.of() + private var orderNo: JsonField = JsonMissing.of() + private var price: JsonField = JsonMissing.of() + private var stampDuty: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + capitalWithdrawal = additionalInfo.capitalWithdrawal + credit = additionalInfo.credit + debit = additionalInfo.debit + incomeDistribution = additionalInfo.incomeDistribution + orderNo = additionalInfo.orderNo + price = additionalInfo.price + stampDuty = additionalInfo.stampDuty + additionalProperties = + additionalInfo.additionalProperties.toMutableMap() + } + + /** Capital withdrawal amount (CDSL MF transactions) */ + fun capitalWithdrawal(capitalWithdrawal: Float) = + capitalWithdrawal(JsonField.of(capitalWithdrawal)) + + /** + * Sets [Builder.capitalWithdrawal] to an arbitrary JSON value. + * + * You should usually call [Builder.capitalWithdrawal] with a well-typed + * [Float] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun capitalWithdrawal(capitalWithdrawal: JsonField) = apply { + this.capitalWithdrawal = capitalWithdrawal + } + + /** Units credited (demat transactions) */ + fun credit(credit: Float) = credit(JsonField.of(credit)) + + /** + * Sets [Builder.credit] to an arbitrary JSON value. + * + * You should usually call [Builder.credit] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun credit(credit: JsonField) = apply { this.credit = credit } + + /** Units debited (demat transactions) */ + fun debit(debit: Float) = debit(JsonField.of(debit)) + + /** + * Sets [Builder.debit] to an arbitrary JSON value. + * + * You should usually call [Builder.debit] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun debit(debit: JsonField) = apply { this.debit = debit } + + /** Income distribution amount (CDSL MF transactions) */ + fun incomeDistribution(incomeDistribution: Float) = + incomeDistribution(JsonField.of(incomeDistribution)) + + /** + * Sets [Builder.incomeDistribution] to an arbitrary JSON value. + * + * You should usually call [Builder.incomeDistribution] with a + * well-typed [Float] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun incomeDistribution(incomeDistribution: JsonField) = apply { + this.incomeDistribution = incomeDistribution + } + + /** Order/transaction reference number (demat transactions) */ + fun orderNo(orderNo: String) = orderNo(JsonField.of(orderNo)) + + /** + * Sets [Builder.orderNo] to an arbitrary JSON value. + * + * You should usually call [Builder.orderNo] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun orderNo(orderNo: JsonField) = apply { + this.orderNo = orderNo + } + + /** Price per unit (NSDL/CDSL MF transactions) */ + fun price(price: Float) = price(JsonField.of(price)) + + /** + * Sets [Builder.price] to an arbitrary JSON value. + * + * You should usually call [Builder.price] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun price(price: JsonField) = apply { this.price = price } + + /** Stamp duty charged */ + fun stampDuty(stampDuty: Float) = stampDuty(JsonField.of(stampDuty)) + + /** + * Sets [Builder.stampDuty] to an arbitrary JSON value. + * + * You should usually call [Builder.stampDuty] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun stampDuty(stampDuty: JsonField) = apply { + this.stampDuty = stampDuty + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } + + capitalWithdrawal() + credit() + debit() + incomeDistribution() + orderNo() + price() + stampDuty() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (capitalWithdrawal.asKnown().isPresent) 1 else 0) + + (if (credit.asKnown().isPresent) 1 else 0) + + (if (debit.asKnown().isPresent) 1 else 0) + + (if (incomeDistribution.asKnown().isPresent) 1 else 0) + + (if (orderNo.asKnown().isPresent) 1 else 0) + + (if (price.asKnown().isPresent) 1 else 0) + + (if (stampDuty.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AdditionalInfo && + capitalWithdrawal == other.capitalWithdrawal && + credit == other.credit && + debit == other.debit && + incomeDistribution == other.incomeDistribution && + orderNo == other.orderNo && + price == other.price && + stampDuty == other.stampDuty && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AdditionalInfo{capitalWithdrawal=$capitalWithdrawal, credit=$credit, debit=$debit, incomeDistribution=$incomeDistribution, orderNo=$orderNo, price=$price, stampDuty=$stampDuty, additionalProperties=$additionalProperties}" + } + + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, + * REVERSAL, UNKNOWN. + */ + class Type + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data + * that doesn't match any known 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. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value + + companion object { + + @JvmField val PURCHASE = of("PURCHASE") + + @JvmField val PURCHASE_SIP = of("PURCHASE_SIP") + + @JvmField val REDEMPTION = of("REDEMPTION") + + @JvmField val SWITCH_IN = of("SWITCH_IN") + + @JvmField val SWITCH_IN_MERGER = of("SWITCH_IN_MERGER") + + @JvmField val SWITCH_OUT = of("SWITCH_OUT") + + @JvmField val SWITCH_OUT_MERGER = of("SWITCH_OUT_MERGER") + + @JvmField val DIVIDEND_PAYOUT = of("DIVIDEND_PAYOUT") + + @JvmField val DIVIDEND_REINVEST = of("DIVIDEND_REINVEST") + + @JvmField val SEGREGATION = of("SEGREGATION") + + @JvmField val STAMP_DUTY_TAX = of("STAMP_DUTY_TAX") + + @JvmField val TDS_TAX = of("TDS_TAX") + + @JvmField val STT_TAX = of("STT_TAX") + + @JvmField val MISC = of("MISC") + + @JvmField val REVERSAL = of("REVERSAL") + + @JvmField val UNKNOWN = of("UNKNOWN") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. 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. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + /** + * An enum member indicating that [Type] was instantiated with an + * unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always + * known or if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + PURCHASE -> Value.PURCHASE + PURCHASE_SIP -> Value.PURCHASE_SIP + REDEMPTION -> Value.REDEMPTION + SWITCH_IN -> Value.SWITCH_IN + SWITCH_IN_MERGER -> Value.SWITCH_IN_MERGER + SWITCH_OUT -> Value.SWITCH_OUT + SWITCH_OUT_MERGER -> Value.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Value.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Value.DIVIDEND_REINVEST + SEGREGATION -> Value.SEGREGATION + STAMP_DUTY_TAX -> Value.STAMP_DUTY_TAX + TDS_TAX -> Value.TDS_TAX + STT_TAX -> Value.STT_TAX + MISC -> Value.MISC + REVERSAL -> Value.REVERSAL + UNKNOWN -> Value.UNKNOWN + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always + * known and don't want to throw for the unknown case. + * + * @throws CasParserInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + PURCHASE -> Known.PURCHASE + PURCHASE_SIP -> Known.PURCHASE_SIP + REDEMPTION -> Known.REDEMPTION + SWITCH_IN -> Known.SWITCH_IN + SWITCH_IN_MERGER -> Known.SWITCH_IN_MERGER + SWITCH_OUT -> Known.SWITCH_OUT + SWITCH_OUT_MERGER -> Known.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Known.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Known.DIVIDEND_REINVEST + SEGREGATION -> Known.SEGREGATION + STAMP_DUTY_TAX -> Known.STAMP_DUTY_TAX + TDS_TAX -> Known.TDS_TAX + STT_TAX -> Known.STT_TAX + MISC -> Known.MISC + REVERSAL -> Known.REVERSAL + UNKNOWN -> Known.UNKNOWN + else -> throw CasParserInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily + * for debugging and generally doesn't throw. + * + * @throws CasParserInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + CasParserInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Transaction && + additionalInfo == other.additionalInfo && + amount == other.amount && + balance == other.balance && + date == other.date && + description == other.description && + dividendRate == other.dividendRate && + nav == other.nav && + type == other.type && + units == other.units && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Transaction{additionalInfo=$additionalInfo, amount=$amount, balance=$balance, date=$date, description=$description, dividendRate=$dividendRate, nav=$nav, type=$type, units=$units, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is CorporateBond && + additionalInfo == other.additionalInfo && isin == other.isin && name == other.name && + transactions == other.transactions && units == other.units && value == other.value && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(additionalInfo, isin, name, units, value, additionalProperties) + Objects.hash( + additionalInfo, + isin, + name, + transactions, + units, + value, + additionalProperties, + ) } override fun hashCode(): Int = hashCode override fun toString() = - "Equity{additionalInfo=$additionalInfo, isin=$isin, name=$name, units=$units, value=$value, additionalProperties=$additionalProperties}" + "CorporateBond{additionalInfo=$additionalInfo, isin=$isin, name=$name, transactions=$transactions, units=$units, value=$value, additionalProperties=$additionalProperties}" } - class GovernmentSecurity + class DematMutualFund + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val additionalInfo: JsonValue, + private val additionalInfo: JsonField, private val isin: JsonField, private val name: JsonField, + private val transactions: JsonField>, private val units: JsonField, private val value: JsonField, private val additionalProperties: MutableMap, @@ -2829,28 +5419,35 @@ private constructor( private constructor( @JsonProperty("additional_info") @ExcludeMissing - additionalInfo: JsonValue = JsonMissing.of(), + additionalInfo: JsonField = JsonMissing.of(), @JsonProperty("isin") @ExcludeMissing isin: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("transactions") + @ExcludeMissing + transactions: JsonField> = JsonMissing.of(), @JsonProperty("units") @ExcludeMissing units: JsonField = JsonMissing.of(), @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), - ) : this(additionalInfo, isin, name, units, value, mutableMapOf()) + ) : this(additionalInfo, isin, name, transactions, units, value, mutableMapOf()) - /** Additional information specific to the government security */ - @JsonProperty("additional_info") - @ExcludeMissing - fun _additionalInfo(): JsonValue = additionalInfo + /** + * Additional information specific to the mutual fund + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") /** - * ISIN code of the government security + * ISIN code of the mutual fund * * @throws CasParserInvalidDataException if the JSON field has an unexpected type * (e.g. if the server responded with an unexpected value). @@ -2858,13 +5455,22 @@ private constructor( fun isin(): Optional = isin.getOptional("isin") /** - * Name of the government security + * Name of the mutual fund * * @throws CasParserInvalidDataException if the JSON field has an unexpected type * (e.g. if the server responded with an unexpected value). */ fun name(): Optional = name.getOptional("name") + /** + * List of transactions for this holding (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun transactions(): Optional> = + transactions.getOptional("transactions") + /** * Number of units held * @@ -2881,6 +5487,16 @@ private constructor( */ fun value(): Optional = value.getOptional("value") + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo + /** * Returns the raw JSON value of [isin]. * @@ -2897,6 +5513,16 @@ private constructor( */ @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + /** + * Returns the raw JSON value of [transactions]. + * + * Unlike [transactions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("transactions") + @ExcludeMissing + fun _transactions(): JsonField> = transactions + /** * Returns the raw JSON value of [units]. * @@ -2928,39 +5554,49 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of - * [GovernmentSecurity]. + * Returns a mutable builder for constructing an instance of [DematMutualFund]. */ @JvmStatic fun builder() = Builder() } - /** A builder for [GovernmentSecurity]. */ + /** A builder for [DematMutualFund]. */ class Builder internal constructor() { - private var additionalInfo: JsonValue = JsonMissing.of() + private var additionalInfo: JsonField = JsonMissing.of() private var isin: JsonField = JsonMissing.of() private var name: JsonField = JsonMissing.of() + private var transactions: JsonField>? = null private var units: JsonField = JsonMissing.of() private var value: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(governmentSecurity: GovernmentSecurity) = apply { - additionalInfo = governmentSecurity.additionalInfo - isin = governmentSecurity.isin - name = governmentSecurity.name - units = governmentSecurity.units - value = governmentSecurity.value - additionalProperties = - governmentSecurity.additionalProperties.toMutableMap() + internal fun from(dematMutualFund: DematMutualFund) = apply { + additionalInfo = dematMutualFund.additionalInfo + isin = dematMutualFund.isin + name = dematMutualFund.name + transactions = dematMutualFund.transactions.map { it.toMutableList() } + units = dematMutualFund.units + value = dematMutualFund.value + additionalProperties = dematMutualFund.additionalProperties.toMutableMap() } - /** Additional information specific to the government security */ - fun additionalInfo(additionalInfo: JsonValue) = apply { + /** Additional information specific to the mutual fund */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) + + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { this.additionalInfo = additionalInfo } - /** ISIN code of the government security */ + /** ISIN code of the mutual fund */ fun isin(isin: String) = isin(JsonField.of(isin)) /** @@ -2972,7 +5608,7 @@ private constructor( */ fun isin(isin: JsonField) = apply { this.isin = isin } - /** Name of the government security */ + /** Name of the mutual fund */ fun name(name: String) = name(JsonField.of(name)) /** @@ -2984,6 +5620,33 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } + /** List of transactions for this holding (beta) */ + fun transactions(transactions: List) = + transactions(JsonField.of(transactions)) + + /** + * Sets [Builder.transactions] to an arbitrary JSON value. + * + * You should usually call [Builder.transactions] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun transactions(transactions: JsonField>) = apply { + this.transactions = transactions.map { it.toMutableList() } + } + + /** + * Adds a single [Transaction] to [transactions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTransaction(transaction: Transaction) = apply { + transactions = + (transactions ?: JsonField.of(mutableListOf())).also { + checkKnown("transactions", it).add(transaction) + } + } + /** Number of units held */ fun units(units: Float) = units(JsonField.of(units)) @@ -3031,15 +5694,16 @@ private constructor( } /** - * Returns an immutable instance of [GovernmentSecurity]. + * Returns an immutable instance of [DematMutualFund]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): GovernmentSecurity = - GovernmentSecurity( + fun build(): DematMutualFund = + DematMutualFund( additionalInfo, isin, name, + (transactions ?: JsonMissing.of()).map { it.toImmutable() }, units, value, additionalProperties.toMutableMap(), @@ -3048,13 +5712,15 @@ private constructor( private var validated: Boolean = false - fun validate(): GovernmentSecurity = apply { + fun validate(): DematMutualFund = apply { if (validated) { return@apply } + additionalInfo().ifPresent { it.validate() } isin() name() + transactions().ifPresent { it.forEach { it.validate() } } units() value() validated = true @@ -3076,3432 +5742,10870 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (isin.asKnown().isPresent) 1 else 0) + + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (isin.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + + (transactions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (if (units.asKnown().isPresent) 1 else 0) + (if (value.asKnown().isPresent) 1 else 0) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** Additional information specific to the mutual fund */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val closeUnits: JsonField, + private val openUnits: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("close_units") + @ExcludeMissing + closeUnits: JsonField = JsonMissing.of(), + @JsonProperty("open_units") + @ExcludeMissing + openUnits: JsonField = JsonMissing.of(), + ) : this(closeUnits, openUnits, mutableMapOf()) + + /** + * Closing balance units for the statement period (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun closeUnits(): Optional = closeUnits.getOptional("close_units") + + /** + * Opening balance units for the statement period (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun openUnits(): Optional = openUnits.getOptional("open_units") + + /** + * Returns the raw JSON value of [closeUnits]. + * + * Unlike [closeUnits], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("close_units") + @ExcludeMissing + fun _closeUnits(): JsonField = closeUnits + + /** + * Returns the raw JSON value of [openUnits]. + * + * Unlike [openUnits], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("open_units") + @ExcludeMissing + fun _openUnits(): JsonField = openUnits + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - return other is GovernmentSecurity && - additionalInfo == other.additionalInfo && - isin == other.isin && - name == other.name && - units == other.units && - value == other.value && - additionalProperties == other.additionalProperties - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - private val hashCode: Int by lazy { - Objects.hash(additionalInfo, isin, name, units, value, additionalProperties) - } + fun toBuilder() = Builder().from(this) - override fun hashCode(): Int = hashCode + companion object { - override fun toString() = - "GovernmentSecurity{additionalInfo=$additionalInfo, isin=$isin, name=$name, units=$units, value=$value, additionalProperties=$additionalProperties}" - } + /** + * Returns a mutable builder for constructing an instance of + * [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { - return other is Holdings && - aifs == other.aifs && - corporateBonds == other.corporateBonds && - dematMutualFunds == other.dematMutualFunds && - equities == other.equities && - governmentSecurities == other.governmentSecurities && - additionalProperties == other.additionalProperties - } + private var closeUnits: JsonField = JsonMissing.of() + private var openUnits: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() - private val hashCode: Int by lazy { - Objects.hash( - aifs, - corporateBonds, - dematMutualFunds, - equities, - governmentSecurities, - additionalProperties, - ) - } + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + closeUnits = additionalInfo.closeUnits + openUnits = additionalInfo.openUnits + additionalProperties = + additionalInfo.additionalProperties.toMutableMap() + } - override fun hashCode(): Int = hashCode + /** Closing balance units for the statement period (beta) */ + fun closeUnits(closeUnits: Float?) = + closeUnits(JsonField.ofNullable(closeUnits)) + + /** + * Alias for [Builder.closeUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun closeUnits(closeUnits: Float) = closeUnits(closeUnits as Float?) + + /** + * Alias for calling [Builder.closeUnits] with `closeUnits.orElse(null)`. + */ + fun closeUnits(closeUnits: Optional) = + closeUnits(closeUnits.getOrNull()) + + /** + * Sets [Builder.closeUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.closeUnits] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun closeUnits(closeUnits: JsonField) = apply { + this.closeUnits = closeUnits + } - override fun toString() = - "Holdings{aifs=$aifs, corporateBonds=$corporateBonds, dematMutualFunds=$dematMutualFunds, equities=$equities, governmentSecurities=$governmentSecurities, additionalProperties=$additionalProperties}" - } + /** Opening balance units for the statement period (beta) */ + fun openUnits(openUnits: Float?) = + openUnits(JsonField.ofNullable(openUnits)) + + /** + * Alias for [Builder.openUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun openUnits(openUnits: Float) = openUnits(openUnits as Float?) + + /** Alias for calling [Builder.openUnits] with `openUnits.orElse(null)`. */ + fun openUnits(openUnits: Optional) = openUnits(openUnits.getOrNull()) + + /** + * Sets [Builder.openUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.openUnits] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun openUnits(openUnits: JsonField) = apply { + this.openUnits = openUnits + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - return other is DematAccount && - additionalInfo == other.additionalInfo && - boId == other.boId && - clientId == other.clientId && - dematType == other.dematType && - dpId == other.dpId && - dpName == other.dpName && - holdings == other.holdings && - value == other.value && - additionalProperties == other.additionalProperties - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - private val hashCode: Int by lazy { - Objects.hash( - additionalInfo, - boId, - clientId, - dematType, - dpId, - dpName, - holdings, - value, - additionalProperties, - ) - } + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } - override fun hashCode(): Int = hashCode + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - override fun toString() = - "DematAccount{additionalInfo=$additionalInfo, boId=$boId, clientId=$clientId, dematType=$dematType, dpId=$dpId, dpName=$dpName, holdings=$holdings, value=$value, additionalProperties=$additionalProperties}" - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - class Insurance - private constructor( - private val lifeInsurancePolicies: JsonField>, - private val additionalProperties: MutableMap, - ) { + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + closeUnits, + openUnits, + additionalProperties.toMutableMap(), + ) + } - @JsonCreator - private constructor( - @JsonProperty("life_insurance_policies") - @ExcludeMissing - lifeInsurancePolicies: JsonField> = JsonMissing.of() - ) : this(lifeInsurancePolicies, mutableMapOf()) + private var validated: Boolean = false - /** - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun lifeInsurancePolicies(): Optional> = - lifeInsurancePolicies.getOptional("life_insurance_policies") + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } - /** - * Returns the raw JSON value of [lifeInsurancePolicies]. - * - * Unlike [lifeInsurancePolicies], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("life_insurance_policies") - @ExcludeMissing - fun _lifeInsurancePolicies(): JsonField> = lifeInsurancePolicies + closeUnits() + openUnits() + validated = true + } - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (closeUnits.asKnown().isPresent) 1 else 0) + + (if (openUnits.asKnown().isPresent) 1 else 0) - fun toBuilder() = Builder().from(this) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - companion object { + return other is AdditionalInfo && + closeUnits == other.closeUnits && + openUnits == other.openUnits && + additionalProperties == other.additionalProperties + } - /** Returns a mutable builder for constructing an instance of [Insurance]. */ - @JvmStatic fun builder() = Builder() - } + private val hashCode: Int by lazy { + Objects.hash(closeUnits, openUnits, additionalProperties) + } - /** A builder for [Insurance]. */ - class Builder internal constructor() { + override fun hashCode(): Int = hashCode - private var lifeInsurancePolicies: JsonField>? = null - private var additionalProperties: MutableMap = mutableMapOf() + override fun toString() = + "AdditionalInfo{closeUnits=$closeUnits, openUnits=$openUnits, additionalProperties=$additionalProperties}" + } - @JvmSynthetic - internal fun from(insurance: Insurance) = apply { - lifeInsurancePolicies = insurance.lifeInsurancePolicies.map { it.toMutableList() } - additionalProperties = insurance.additionalProperties.toMutableMap() - } + /** + * Unified transaction schema for all holding types (MF folios, equities, bonds, + * etc.) + */ + class Transaction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, + private val amount: JsonField, + private val balance: JsonField, + private val date: JsonField, + private val description: JsonField, + private val dividendRate: JsonField, + private val nav: JsonField, + private val type: JsonField, + private val units: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("amount") + @ExcludeMissing + amount: JsonField = JsonMissing.of(), + @JsonProperty("balance") + @ExcludeMissing + balance: JsonField = JsonMissing.of(), + @JsonProperty("date") + @ExcludeMissing + date: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("dividend_rate") + @ExcludeMissing + dividendRate: JsonField = JsonMissing.of(), + @JsonProperty("nav") + @ExcludeMissing + nav: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + @JsonProperty("units") + @ExcludeMissing + units: JsonField = JsonMissing.of(), + ) : this( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + mutableMapOf(), + ) - fun lifeInsurancePolicies(lifeInsurancePolicies: List) = - lifeInsurancePolicies(JsonField.of(lifeInsurancePolicies)) + /** + * Additional transaction-specific fields that vary by source + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") - /** - * Sets [Builder.lifeInsurancePolicies] to an arbitrary JSON value. - * - * You should usually call [Builder.lifeInsurancePolicies] with a well-typed - * `List` value instead. This method is primarily for setting the - * field to an undocumented or not yet supported value. - */ - fun lifeInsurancePolicies(lifeInsurancePolicies: JsonField>) = - apply { - this.lifeInsurancePolicies = lifeInsurancePolicies.map { it.toMutableList() } - } + /** + * Transaction amount in currency (computed from units × price/NAV) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun amount(): Optional = amount.getOptional("amount") - /** - * Adds a single [LifeInsurancePolicy] to [lifeInsurancePolicies]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addLifeInsurancePolicy(lifeInsurancePolicy: LifeInsurancePolicy) = apply { - lifeInsurancePolicies = - (lifeInsurancePolicies ?: JsonField.of(mutableListOf())).also { - checkKnown("lifeInsurancePolicies", it).add(lifeInsurancePolicy) - } - } + /** + * Balance units after transaction + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun balance(): Optional = balance.getOptional("balance") - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** + * Transaction date (YYYY-MM-DD) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun date(): Optional = date.getOptional("date") - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + /** + * Transaction description/particulars + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun description(): Optional = description.getOptional("description") - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + /** + * Dividend rate (for DIVIDEND_PAYOUT transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun dividendRate(): Optional = dividendRate.getOptional("dividend_rate") - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + /** + * NAV/price per unit on transaction date + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun nav(): Optional = nav.getOptional("nav") - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, + * REVERSAL, UNKNOWN. + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") - /** - * Returns an immutable instance of [Insurance]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Insurance = - Insurance( - (lifeInsurancePolicies ?: JsonMissing.of()).map { it.toImmutable() }, - additionalProperties.toMutableMap(), - ) - } + /** + * Number of units involved in transaction + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun units(): Optional = units.getOptional("units") - private var validated: Boolean = false + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo - fun validate(): Insurance = apply { - if (validated) { - return@apply - } + /** + * Returns the raw JSON value of [amount]. + * + * Unlike [amount], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("amount") @ExcludeMissing fun _amount(): JsonField = amount - lifeInsurancePolicies().ifPresent { it.forEach { it.validate() } } - validated = true - } + /** + * Returns the raw JSON value of [balance]. + * + * Unlike [balance], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("balance") + @ExcludeMissing + fun _balance(): JsonField = balance - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + /** + * Returns the raw JSON value of [date]. + * + * Unlike [date], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("date") @ExcludeMissing fun _date(): JsonField = date - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (lifeInsurancePolicies.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description - class LifeInsurancePolicy - private constructor( - private val additionalInfo: JsonValue, - private val lifeAssured: JsonField, - private val policyName: JsonField, - private val policyNumber: JsonField, - private val premiumAmount: JsonField, - private val premiumFrequency: JsonField, - private val provider: JsonField, - private val status: JsonField, - private val sumAssured: JsonField, - private val additionalProperties: MutableMap, - ) { + /** + * Returns the raw JSON value of [dividendRate]. + * + * Unlike [dividendRate], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("dividend_rate") + @ExcludeMissing + fun _dividendRate(): JsonField = dividendRate - @JsonCreator - private constructor( - @JsonProperty("additional_info") - @ExcludeMissing - additionalInfo: JsonValue = JsonMissing.of(), - @JsonProperty("life_assured") - @ExcludeMissing - lifeAssured: JsonField = JsonMissing.of(), - @JsonProperty("policy_name") - @ExcludeMissing - policyName: JsonField = JsonMissing.of(), - @JsonProperty("policy_number") - @ExcludeMissing - policyNumber: JsonField = JsonMissing.of(), - @JsonProperty("premium_amount") - @ExcludeMissing - premiumAmount: JsonField = JsonMissing.of(), - @JsonProperty("premium_frequency") - @ExcludeMissing - premiumFrequency: JsonField = JsonMissing.of(), - @JsonProperty("provider") - @ExcludeMissing - provider: JsonField = JsonMissing.of(), - @JsonProperty("status") - @ExcludeMissing - status: JsonField = JsonMissing.of(), - @JsonProperty("sum_assured") - @ExcludeMissing - sumAssured: JsonField = JsonMissing.of(), - ) : this( - additionalInfo, - lifeAssured, - policyName, - policyNumber, - premiumAmount, - premiumFrequency, - provider, - status, - sumAssured, - mutableMapOf(), - ) + /** + * Returns the raw JSON value of [nav]. + * + * Unlike [nav], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("nav") @ExcludeMissing fun _nav(): JsonField = nav - /** Additional information specific to the policy */ - @JsonProperty("additional_info") - @ExcludeMissing - fun _additionalInfo(): JsonValue = additionalInfo + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type - /** - * Name of the life assured - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun lifeAssured(): Optional = lifeAssured.getOptional("life_assured") + /** + * Returns the raw JSON value of [units]. + * + * Unlike [units], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units - /** - * Name of the insurance policy - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun policyName(): Optional = policyName.getOptional("policy_name") + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - /** - * Insurance policy number - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun policyNumber(): Optional = policyNumber.getOptional("policy_number") + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - /** - * Premium amount - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun premiumAmount(): Optional = premiumAmount.getOptional("premium_amount") + fun toBuilder() = Builder().from(this) - /** - * Frequency of premium payment (e.g., Annual, Monthly) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun premiumFrequency(): Optional = - premiumFrequency.getOptional("premium_frequency") + companion object { - /** - * Insurance company name - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun provider(): Optional = provider.getOptional("provider") + /** + * Returns a mutable builder for constructing an instance of [Transaction]. + */ + @JvmStatic fun builder() = Builder() + } - /** - * Status of the policy (e.g., Active, Lapsed) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun status(): Optional = status.getOptional("status") + /** A builder for [Transaction]. */ + class Builder internal constructor() { + + private var additionalInfo: JsonField = JsonMissing.of() + private var amount: JsonField = JsonMissing.of() + private var balance: JsonField = JsonMissing.of() + private var date: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var dividendRate: JsonField = JsonMissing.of() + private var nav: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var units: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(transaction: Transaction) = apply { + additionalInfo = transaction.additionalInfo + amount = transaction.amount + balance = transaction.balance + date = transaction.date + description = transaction.description + dividendRate = transaction.dividendRate + nav = transaction.nav + type = transaction.type + units = transaction.units + additionalProperties = transaction.additionalProperties.toMutableMap() + } - /** - * Sum assured amount - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun sumAssured(): Optional = sumAssured.getOptional("sum_assured") + /** Additional transaction-specific fields that vary by source */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) + + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { + this.additionalInfo = additionalInfo + } - /** - * Returns the raw JSON value of [lifeAssured]. - * - * Unlike [lifeAssured], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("life_assured") - @ExcludeMissing - fun _lifeAssured(): JsonField = lifeAssured + /** Transaction amount in currency (computed from units × price/NAV) */ + fun amount(amount: Float?) = amount(JsonField.ofNullable(amount)) + + /** + * Alias for [Builder.amount]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun amount(amount: Float) = amount(amount as Float?) + + /** Alias for calling [Builder.amount] with `amount.orElse(null)`. */ + fun amount(amount: Optional) = amount(amount.getOrNull()) + + /** + * Sets [Builder.amount] to an arbitrary JSON value. + * + * You should usually call [Builder.amount] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun amount(amount: JsonField) = apply { this.amount = amount } + + /** Balance units after transaction */ + fun balance(balance: Float) = balance(JsonField.of(balance)) + + /** + * Sets [Builder.balance] to an arbitrary JSON value. + * + * You should usually call [Builder.balance] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun balance(balance: JsonField) = apply { this.balance = balance } + + /** Transaction date (YYYY-MM-DD) */ + fun date(date: LocalDate) = date(JsonField.of(date)) + + /** + * Sets [Builder.date] to an arbitrary JSON value. + * + * You should usually call [Builder.date] with a well-typed [LocalDate] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun date(date: JsonField) = apply { this.date = date } + + /** Transaction description/particulars */ + fun description(description: String) = + description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } - /** - * Returns the raw JSON value of [policyName]. - * - * Unlike [policyName], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("policy_name") - @ExcludeMissing - fun _policyName(): JsonField = policyName + /** Dividend rate (for DIVIDEND_PAYOUT transactions) */ + fun dividendRate(dividendRate: Float?) = + dividendRate(JsonField.ofNullable(dividendRate)) + + /** + * Alias for [Builder.dividendRate]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun dividendRate(dividendRate: Float) = dividendRate(dividendRate as Float?) + + /** + * Alias for calling [Builder.dividendRate] with + * `dividendRate.orElse(null)`. + */ + fun dividendRate(dividendRate: Optional) = + dividendRate(dividendRate.getOrNull()) + + /** + * Sets [Builder.dividendRate] to an arbitrary JSON value. + * + * You should usually call [Builder.dividendRate] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun dividendRate(dividendRate: JsonField) = apply { + this.dividendRate = dividendRate + } - /** - * Returns the raw JSON value of [policyNumber]. - * - * Unlike [policyNumber], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("policy_number") - @ExcludeMissing - fun _policyNumber(): JsonField = policyNumber + /** NAV/price per unit on transaction date */ + fun nav(nav: Float?) = nav(JsonField.ofNullable(nav)) + + /** + * Alias for [Builder.nav]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun nav(nav: Float) = nav(nav as Float?) + + /** Alias for calling [Builder.nav] with `nav.orElse(null)`. */ + fun nav(nav: Optional) = nav(nav.getOrNull()) + + /** + * Sets [Builder.nav] to an arbitrary JSON value. + * + * You should usually call [Builder.nav] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun nav(nav: JsonField) = apply { this.nav = nav } + + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, + * DIVIDEND_PAYOUT, DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, + * STT_TAX, MISC, REVERSAL, UNKNOWN. + */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + /** Number of units involved in transaction */ + fun units(units: Float) = units(JsonField.of(units)) + + /** + * Sets [Builder.units] to an arbitrary JSON value. + * + * You should usually call [Builder.units] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun units(units: JsonField) = apply { this.units = units } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - /** - * Returns the raw JSON value of [premiumAmount]. - * - * Unlike [premiumAmount], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("premium_amount") - @ExcludeMissing - fun _premiumAmount(): JsonField = premiumAmount + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } - /** - * Returns the raw JSON value of [premiumFrequency]. - * - * Unlike [premiumFrequency], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("premium_frequency") - @ExcludeMissing - fun _premiumFrequency(): JsonField = premiumFrequency + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - /** - * Returns the raw JSON value of [provider]. - * - * Unlike [provider], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - /** - * Returns the raw JSON value of [status]. - * - * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + /** + * Returns an immutable instance of [Transaction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Transaction = + Transaction( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + additionalProperties.toMutableMap(), + ) + } - /** - * Returns the raw JSON value of [sumAssured]. - * - * Unlike [sumAssured], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("sum_assured") - @ExcludeMissing - fun _sumAssured(): JsonField = sumAssured + private var validated: Boolean = false - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + fun validate(): Transaction = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + additionalInfo().ifPresent { it.validate() } + amount() + balance() + date() + description() + dividendRate() + nav() + type().ifPresent { it.validate() } + units() + validated = true + } - fun toBuilder() = Builder().from(this) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } - companion object { + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (amount.asKnown().isPresent) 1 else 0) + + (if (balance.asKnown().isPresent) 1 else 0) + + (if (date.asKnown().isPresent) 1 else 0) + + (if (description.asKnown().isPresent) 1 else 0) + + (if (dividendRate.asKnown().isPresent) 1 else 0) + + (if (nav.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (units.asKnown().isPresent) 1 else 0) + + /** Additional transaction-specific fields that vary by source */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val capitalWithdrawal: JsonField, + private val credit: JsonField, + private val debit: JsonField, + private val incomeDistribution: JsonField, + private val orderNo: JsonField, + private val price: JsonField, + private val stampDuty: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("capital_withdrawal") + @ExcludeMissing + capitalWithdrawal: JsonField = JsonMissing.of(), + @JsonProperty("credit") + @ExcludeMissing + credit: JsonField = JsonMissing.of(), + @JsonProperty("debit") + @ExcludeMissing + debit: JsonField = JsonMissing.of(), + @JsonProperty("income_distribution") + @ExcludeMissing + incomeDistribution: JsonField = JsonMissing.of(), + @JsonProperty("order_no") + @ExcludeMissing + orderNo: JsonField = JsonMissing.of(), + @JsonProperty("price") + @ExcludeMissing + price: JsonField = JsonMissing.of(), + @JsonProperty("stamp_duty") + @ExcludeMissing + stampDuty: JsonField = JsonMissing.of(), + ) : this( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + mutableMapOf(), + ) - /** - * Returns a mutable builder for constructing an instance of [LifeInsurancePolicy]. - */ - @JvmStatic fun builder() = Builder() - } + /** + * Capital withdrawal amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun capitalWithdrawal(): Optional = + capitalWithdrawal.getOptional("capital_withdrawal") + + /** + * Units credited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun credit(): Optional = credit.getOptional("credit") + + /** + * Units debited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun debit(): Optional = debit.getOptional("debit") + + /** + * Income distribution amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun incomeDistribution(): Optional = + incomeDistribution.getOptional("income_distribution") + + /** + * Order/transaction reference number (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun orderNo(): Optional = orderNo.getOptional("order_no") + + /** + * Price per unit (NSDL/CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun price(): Optional = price.getOptional("price") + + /** + * Stamp duty charged + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun stampDuty(): Optional = stampDuty.getOptional("stamp_duty") + + /** + * Returns the raw JSON value of [capitalWithdrawal]. + * + * Unlike [capitalWithdrawal], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("capital_withdrawal") + @ExcludeMissing + fun _capitalWithdrawal(): JsonField = capitalWithdrawal + + /** + * Returns the raw JSON value of [credit]. + * + * Unlike [credit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("credit") + @ExcludeMissing + fun _credit(): JsonField = credit + + /** + * Returns the raw JSON value of [debit]. + * + * Unlike [debit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("debit") + @ExcludeMissing + fun _debit(): JsonField = debit + + /** + * Returns the raw JSON value of [incomeDistribution]. + * + * Unlike [incomeDistribution], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("income_distribution") + @ExcludeMissing + fun _incomeDistribution(): JsonField = incomeDistribution + + /** + * Returns the raw JSON value of [orderNo]. + * + * Unlike [orderNo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("order_no") + @ExcludeMissing + fun _orderNo(): JsonField = orderNo + + /** + * Returns the raw JSON value of [price]. + * + * Unlike [price], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("price") + @ExcludeMissing + fun _price(): JsonField = price + + /** + * Returns the raw JSON value of [stampDuty]. + * + * Unlike [stampDuty], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("stamp_duty") + @ExcludeMissing + fun _stampDuty(): JsonField = stampDuty + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - /** A builder for [LifeInsurancePolicy]. */ - class Builder internal constructor() { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - private var additionalInfo: JsonValue = JsonMissing.of() - private var lifeAssured: JsonField = JsonMissing.of() - private var policyName: JsonField = JsonMissing.of() - private var policyNumber: JsonField = JsonMissing.of() - private var premiumAmount: JsonField = JsonMissing.of() - private var premiumFrequency: JsonField = JsonMissing.of() - private var provider: JsonField = JsonMissing.of() - private var status: JsonField = JsonMissing.of() - private var sumAssured: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + fun toBuilder() = Builder().from(this) - @JvmSynthetic - internal fun from(lifeInsurancePolicy: LifeInsurancePolicy) = apply { - additionalInfo = lifeInsurancePolicy.additionalInfo - lifeAssured = lifeInsurancePolicy.lifeAssured - policyName = lifeInsurancePolicy.policyName - policyNumber = lifeInsurancePolicy.policyNumber - premiumAmount = lifeInsurancePolicy.premiumAmount - premiumFrequency = lifeInsurancePolicy.premiumFrequency - provider = lifeInsurancePolicy.provider - status = lifeInsurancePolicy.status - sumAssured = lifeInsurancePolicy.sumAssured - additionalProperties = lifeInsurancePolicy.additionalProperties.toMutableMap() - } + companion object { - /** Additional information specific to the policy */ - fun additionalInfo(additionalInfo: JsonValue) = apply { - this.additionalInfo = additionalInfo - } + /** + * Returns a mutable builder for constructing an instance of + * [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } - /** Name of the life assured */ - fun lifeAssured(lifeAssured: String) = lifeAssured(JsonField.of(lifeAssured)) + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { + + private var capitalWithdrawal: JsonField = JsonMissing.of() + private var credit: JsonField = JsonMissing.of() + private var debit: JsonField = JsonMissing.of() + private var incomeDistribution: JsonField = JsonMissing.of() + private var orderNo: JsonField = JsonMissing.of() + private var price: JsonField = JsonMissing.of() + private var stampDuty: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + capitalWithdrawal = additionalInfo.capitalWithdrawal + credit = additionalInfo.credit + debit = additionalInfo.debit + incomeDistribution = additionalInfo.incomeDistribution + orderNo = additionalInfo.orderNo + price = additionalInfo.price + stampDuty = additionalInfo.stampDuty + additionalProperties = + additionalInfo.additionalProperties.toMutableMap() + } + + /** Capital withdrawal amount (CDSL MF transactions) */ + fun capitalWithdrawal(capitalWithdrawal: Float) = + capitalWithdrawal(JsonField.of(capitalWithdrawal)) + + /** + * Sets [Builder.capitalWithdrawal] to an arbitrary JSON value. + * + * You should usually call [Builder.capitalWithdrawal] with a well-typed + * [Float] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun capitalWithdrawal(capitalWithdrawal: JsonField) = apply { + this.capitalWithdrawal = capitalWithdrawal + } + + /** Units credited (demat transactions) */ + fun credit(credit: Float) = credit(JsonField.of(credit)) + + /** + * Sets [Builder.credit] to an arbitrary JSON value. + * + * You should usually call [Builder.credit] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun credit(credit: JsonField) = apply { this.credit = credit } + + /** Units debited (demat transactions) */ + fun debit(debit: Float) = debit(JsonField.of(debit)) + + /** + * Sets [Builder.debit] to an arbitrary JSON value. + * + * You should usually call [Builder.debit] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun debit(debit: JsonField) = apply { this.debit = debit } + + /** Income distribution amount (CDSL MF transactions) */ + fun incomeDistribution(incomeDistribution: Float) = + incomeDistribution(JsonField.of(incomeDistribution)) + + /** + * Sets [Builder.incomeDistribution] to an arbitrary JSON value. + * + * You should usually call [Builder.incomeDistribution] with a + * well-typed [Float] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun incomeDistribution(incomeDistribution: JsonField) = apply { + this.incomeDistribution = incomeDistribution + } + + /** Order/transaction reference number (demat transactions) */ + fun orderNo(orderNo: String) = orderNo(JsonField.of(orderNo)) + + /** + * Sets [Builder.orderNo] to an arbitrary JSON value. + * + * You should usually call [Builder.orderNo] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun orderNo(orderNo: JsonField) = apply { + this.orderNo = orderNo + } + + /** Price per unit (NSDL/CDSL MF transactions) */ + fun price(price: Float) = price(JsonField.of(price)) + + /** + * Sets [Builder.price] to an arbitrary JSON value. + * + * You should usually call [Builder.price] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun price(price: JsonField) = apply { this.price = price } + + /** Stamp duty charged */ + fun stampDuty(stampDuty: Float) = stampDuty(JsonField.of(stampDuty)) + + /** + * Sets [Builder.stampDuty] to an arbitrary JSON value. + * + * You should usually call [Builder.stampDuty] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun stampDuty(stampDuty: JsonField) = apply { + this.stampDuty = stampDuty + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties.toMutableMap(), + ) + } - /** - * Sets [Builder.lifeAssured] to an arbitrary JSON value. - * - * You should usually call [Builder.lifeAssured] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun lifeAssured(lifeAssured: JsonField) = apply { - this.lifeAssured = lifeAssured + private var validated: Boolean = false + + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } + + capitalWithdrawal() + credit() + debit() + incomeDistribution() + orderNo() + price() + stampDuty() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (capitalWithdrawal.asKnown().isPresent) 1 else 0) + + (if (credit.asKnown().isPresent) 1 else 0) + + (if (debit.asKnown().isPresent) 1 else 0) + + (if (incomeDistribution.asKnown().isPresent) 1 else 0) + + (if (orderNo.asKnown().isPresent) 1 else 0) + + (if (price.asKnown().isPresent) 1 else 0) + + (if (stampDuty.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AdditionalInfo && + capitalWithdrawal == other.capitalWithdrawal && + credit == other.credit && + debit == other.debit && + incomeDistribution == other.incomeDistribution && + orderNo == other.orderNo && + price == other.price && + stampDuty == other.stampDuty && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AdditionalInfo{capitalWithdrawal=$capitalWithdrawal, credit=$credit, debit=$debit, incomeDistribution=$incomeDistribution, orderNo=$orderNo, price=$price, stampDuty=$stampDuty, additionalProperties=$additionalProperties}" + } + + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, + * REVERSAL, UNKNOWN. + */ + class Type + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data + * that doesn't match any known 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. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value + + companion object { + + @JvmField val PURCHASE = of("PURCHASE") + + @JvmField val PURCHASE_SIP = of("PURCHASE_SIP") + + @JvmField val REDEMPTION = of("REDEMPTION") + + @JvmField val SWITCH_IN = of("SWITCH_IN") + + @JvmField val SWITCH_IN_MERGER = of("SWITCH_IN_MERGER") + + @JvmField val SWITCH_OUT = of("SWITCH_OUT") + + @JvmField val SWITCH_OUT_MERGER = of("SWITCH_OUT_MERGER") + + @JvmField val DIVIDEND_PAYOUT = of("DIVIDEND_PAYOUT") + + @JvmField val DIVIDEND_REINVEST = of("DIVIDEND_REINVEST") + + @JvmField val SEGREGATION = of("SEGREGATION") + + @JvmField val STAMP_DUTY_TAX = of("STAMP_DUTY_TAX") + + @JvmField val TDS_TAX = of("TDS_TAX") + + @JvmField val STT_TAX = of("STT_TAX") + + @JvmField val MISC = of("MISC") + + @JvmField val REVERSAL = of("REVERSAL") + + @JvmField val UNKNOWN = of("UNKNOWN") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. 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. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + /** + * An enum member indicating that [Type] was instantiated with an + * unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always + * known or if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + PURCHASE -> Value.PURCHASE + PURCHASE_SIP -> Value.PURCHASE_SIP + REDEMPTION -> Value.REDEMPTION + SWITCH_IN -> Value.SWITCH_IN + SWITCH_IN_MERGER -> Value.SWITCH_IN_MERGER + SWITCH_OUT -> Value.SWITCH_OUT + SWITCH_OUT_MERGER -> Value.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Value.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Value.DIVIDEND_REINVEST + SEGREGATION -> Value.SEGREGATION + STAMP_DUTY_TAX -> Value.STAMP_DUTY_TAX + TDS_TAX -> Value.TDS_TAX + STT_TAX -> Value.STT_TAX + MISC -> Value.MISC + REVERSAL -> Value.REVERSAL + UNKNOWN -> Value.UNKNOWN + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always + * known and don't want to throw for the unknown case. + * + * @throws CasParserInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + PURCHASE -> Known.PURCHASE + PURCHASE_SIP -> Known.PURCHASE_SIP + REDEMPTION -> Known.REDEMPTION + SWITCH_IN -> Known.SWITCH_IN + SWITCH_IN_MERGER -> Known.SWITCH_IN_MERGER + SWITCH_OUT -> Known.SWITCH_OUT + SWITCH_OUT_MERGER -> Known.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Known.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Known.DIVIDEND_REINVEST + SEGREGATION -> Known.SEGREGATION + STAMP_DUTY_TAX -> Known.STAMP_DUTY_TAX + TDS_TAX -> Known.TDS_TAX + STT_TAX -> Known.STT_TAX + MISC -> Known.MISC + REVERSAL -> Known.REVERSAL + UNKNOWN -> Known.UNKNOWN + else -> throw CasParserInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily + * for debugging and generally doesn't throw. + * + * @throws CasParserInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + CasParserInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Transaction && + additionalInfo == other.additionalInfo && + amount == other.amount && + balance == other.balance && + date == other.date && + description == other.description && + dividendRate == other.dividendRate && + nav == other.nav && + type == other.type && + units == other.units && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Transaction{additionalInfo=$additionalInfo, amount=$amount, balance=$balance, date=$date, description=$description, dividendRate=$dividendRate, nav=$nav, type=$type, units=$units, additionalProperties=$additionalProperties}" } - /** Name of the insurance policy */ - fun policyName(policyName: String) = policyName(JsonField.of(policyName)) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - /** - * Sets [Builder.policyName] to an arbitrary JSON value. - * - * You should usually call [Builder.policyName] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun policyName(policyName: JsonField) = apply { - this.policyName = policyName + return other is DematMutualFund && + additionalInfo == other.additionalInfo && + isin == other.isin && + name == other.name && + transactions == other.transactions && + units == other.units && + value == other.value && + additionalProperties == other.additionalProperties } - /** Insurance policy number */ - fun policyNumber(policyNumber: String) = policyNumber(JsonField.of(policyNumber)) + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + isin, + name, + transactions, + units, + value, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "DematMutualFund{additionalInfo=$additionalInfo, isin=$isin, name=$name, transactions=$transactions, units=$units, value=$value, additionalProperties=$additionalProperties}" + } + + class Equity + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, + private val isin: JsonField, + private val name: JsonField, + private val transactions: JsonField>, + private val units: JsonField, + private val value: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("isin") + @ExcludeMissing + isin: JsonField = JsonMissing.of(), + @JsonProperty("name") + @ExcludeMissing + name: JsonField = JsonMissing.of(), + @JsonProperty("transactions") + @ExcludeMissing + transactions: JsonField> = JsonMissing.of(), + @JsonProperty("units") + @ExcludeMissing + units: JsonField = JsonMissing.of(), + @JsonProperty("value") + @ExcludeMissing + value: JsonField = JsonMissing.of(), + ) : this(additionalInfo, isin, name, transactions, units, value, mutableMapOf()) /** - * Sets [Builder.policyNumber] to an arbitrary JSON value. + * Additional information specific to the equity * - * You should usually call [Builder.policyNumber] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). */ - fun policyNumber(policyNumber: JsonField) = apply { - this.policyNumber = policyNumber - } + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") - /** Premium amount */ - fun premiumAmount(premiumAmount: Float) = premiumAmount(JsonField.of(premiumAmount)) + /** + * ISIN code of the equity + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun isin(): Optional = isin.getOptional("isin") /** - * Sets [Builder.premiumAmount] to an arbitrary JSON value. + * Name of the equity * - * You should usually call [Builder.premiumAmount] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). */ - fun premiumAmount(premiumAmount: JsonField) = apply { - this.premiumAmount = premiumAmount - } + fun name(): Optional = name.getOptional("name") - /** Frequency of premium payment (e.g., Annual, Monthly) */ - fun premiumFrequency(premiumFrequency: String) = - premiumFrequency(JsonField.of(premiumFrequency)) + /** + * List of transactions for this holding (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun transactions(): Optional> = + transactions.getOptional("transactions") /** - * Sets [Builder.premiumFrequency] to an arbitrary JSON value. + * Number of units held * - * You should usually call [Builder.premiumFrequency] with a well-typed [String] - * value instead. This method is primarily for setting the field to an undocumented - * or not yet supported value. + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). */ - fun premiumFrequency(premiumFrequency: JsonField) = apply { - this.premiumFrequency = premiumFrequency - } + fun units(): Optional = units.getOptional("units") - /** Insurance company name */ - fun provider(provider: String) = provider(JsonField.of(provider)) + /** + * Current market value of the holding + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun value(): Optional = value.getOptional("value") /** - * Sets [Builder.provider] to an arbitrary JSON value. + * Returns the raw JSON value of [additionalInfo]. * - * You should usually call [Builder.provider] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. */ - fun provider(provider: JsonField) = apply { this.provider = provider } + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo - /** Status of the policy (e.g., Active, Lapsed) */ - fun status(status: String) = status(JsonField.of(status)) + /** + * Returns the raw JSON value of [isin]. + * + * Unlike [isin], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("isin") @ExcludeMissing fun _isin(): JsonField = isin /** - * Sets [Builder.status] to an arbitrary JSON value. + * Returns the raw JSON value of [name]. * - * You should usually call [Builder.status] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected + * type. */ - fun status(status: JsonField) = apply { this.status = status } + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** Sum assured amount */ - fun sumAssured(sumAssured: Float) = sumAssured(JsonField.of(sumAssured)) + /** + * Returns the raw JSON value of [transactions]. + * + * Unlike [transactions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("transactions") + @ExcludeMissing + fun _transactions(): JsonField> = transactions /** - * Sets [Builder.sumAssured] to an arbitrary JSON value. + * Returns the raw JSON value of [units]. * - * You should usually call [Builder.sumAssured] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. + * Unlike [units], this method doesn't throw if the JSON field has an unexpected + * type. */ - fun sumAssured(sumAssured: JsonField) = apply { - this.sumAssured = sumAssured - } + @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value - fun putAdditionalProperty(key: String, value: JsonValue) = apply { + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - /** - * Returns an immutable instance of [LifeInsurancePolicy]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): LifeInsurancePolicy = - LifeInsurancePolicy( - additionalInfo, - lifeAssured, - policyName, - policyNumber, - premiumAmount, - premiumFrequency, - provider, - status, - sumAssured, - additionalProperties.toMutableMap(), - ) - } + fun toBuilder() = Builder().from(this) - private var validated: Boolean = false + companion object { - fun validate(): LifeInsurancePolicy = apply { - if (validated) { - return@apply + /** Returns a mutable builder for constructing an instance of [Equity]. */ + @JvmStatic fun builder() = Builder() } - lifeAssured() - policyName() - policyNumber() - premiumAmount() - premiumFrequency() - provider() - status() - sumAssured() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + /** A builder for [Equity]. */ + class Builder internal constructor() { - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (lifeAssured.asKnown().isPresent) 1 else 0) + - (if (policyName.asKnown().isPresent) 1 else 0) + - (if (policyNumber.asKnown().isPresent) 1 else 0) + - (if (premiumAmount.asKnown().isPresent) 1 else 0) + - (if (premiumFrequency.asKnown().isPresent) 1 else 0) + - (if (provider.asKnown().isPresent) 1 else 0) + - (if (status.asKnown().isPresent) 1 else 0) + - (if (sumAssured.asKnown().isPresent) 1 else 0) + private var additionalInfo: JsonField = JsonMissing.of() + private var isin: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var transactions: JsonField>? = null + private var units: JsonField = JsonMissing.of() + private var value: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + @JvmSynthetic + internal fun from(equity: Equity) = apply { + additionalInfo = equity.additionalInfo + isin = equity.isin + name = equity.name + transactions = equity.transactions.map { it.toMutableList() } + units = equity.units + value = equity.value + additionalProperties = equity.additionalProperties.toMutableMap() + } - return other is LifeInsurancePolicy && - additionalInfo == other.additionalInfo && - lifeAssured == other.lifeAssured && - policyName == other.policyName && - policyNumber == other.policyNumber && - premiumAmount == other.premiumAmount && - premiumFrequency == other.premiumFrequency && - provider == other.provider && - status == other.status && - sumAssured == other.sumAssured && - additionalProperties == other.additionalProperties - } + /** Additional information specific to the equity */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) - private val hashCode: Int by lazy { - Objects.hash( - additionalInfo, - lifeAssured, - policyName, - policyNumber, - premiumAmount, - premiumFrequency, - provider, - status, - sumAssured, - additionalProperties, - ) - } + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { + this.additionalInfo = additionalInfo + } - override fun hashCode(): Int = hashCode + /** ISIN code of the equity */ + fun isin(isin: String) = isin(JsonField.of(isin)) - override fun toString() = - "LifeInsurancePolicy{additionalInfo=$additionalInfo, lifeAssured=$lifeAssured, policyName=$policyName, policyNumber=$policyNumber, premiumAmount=$premiumAmount, premiumFrequency=$premiumFrequency, provider=$provider, status=$status, sumAssured=$sumAssured, additionalProperties=$additionalProperties}" - } + /** + * Sets [Builder.isin] to an arbitrary JSON value. + * + * You should usually call [Builder.isin] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun isin(isin: JsonField) = apply { this.isin = isin } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** Name of the equity */ + fun name(name: String) = name(JsonField.of(name)) - return other is Insurance && - lifeInsurancePolicies == other.lifeInsurancePolicies && - additionalProperties == other.additionalProperties - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } - private val hashCode: Int by lazy { - Objects.hash(lifeInsurancePolicies, additionalProperties) - } + /** List of transactions for this holding (beta) */ + fun transactions(transactions: List) = + transactions(JsonField.of(transactions)) - override fun hashCode(): Int = hashCode + /** + * Sets [Builder.transactions] to an arbitrary JSON value. + * + * You should usually call [Builder.transactions] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun transactions(transactions: JsonField>) = apply { + this.transactions = transactions.map { it.toMutableList() } + } - override fun toString() = - "Insurance{lifeInsurancePolicies=$lifeInsurancePolicies, additionalProperties=$additionalProperties}" - } + /** + * Adds a single [Transaction] to [transactions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTransaction(transaction: Transaction) = apply { + transactions = + (transactions ?: JsonField.of(mutableListOf())).also { + checkKnown("transactions", it).add(transaction) + } + } - class Investor - private constructor( - private val address: JsonField, - private val casId: JsonField, - private val email: JsonField, - private val mobile: JsonField, - private val name: JsonField, - private val pan: JsonField, - private val pincode: JsonField, - private val additionalProperties: MutableMap, - ) { + /** Number of units held */ + fun units(units: Float) = units(JsonField.of(units)) - @JsonCreator - private constructor( - @JsonProperty("address") @ExcludeMissing address: JsonField = JsonMissing.of(), - @JsonProperty("cas_id") @ExcludeMissing casId: JsonField = JsonMissing.of(), - @JsonProperty("email") @ExcludeMissing email: JsonField = JsonMissing.of(), - @JsonProperty("mobile") @ExcludeMissing mobile: JsonField = JsonMissing.of(), - @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), - @JsonProperty("pan") @ExcludeMissing pan: JsonField = JsonMissing.of(), - @JsonProperty("pincode") @ExcludeMissing pincode: JsonField = JsonMissing.of(), - ) : this(address, casId, email, mobile, name, pan, pincode, mutableMapOf()) + /** + * Sets [Builder.units] to an arbitrary JSON value. + * + * You should usually call [Builder.units] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun units(units: JsonField) = apply { this.units = units } - /** - * Address of the investor - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun address(): Optional = address.getOptional("address") + /** Current market value of the holding */ + fun value(value: Float) = value(JsonField.of(value)) - /** - * CAS ID of the investor (only for NSDL and CDSL) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun casId(): Optional = casId.getOptional("cas_id") + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun value(value: JsonField) = apply { this.value = value } - /** - * Email address of the investor - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun email(): Optional = email.getOptional("email") + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - /** - * Mobile number of the investor - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun mobile(): Optional = mobile.getOptional("mobile") + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - /** - * Name of the investor - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun name(): Optional = name.getOptional("name") + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } - /** - * PAN (Permanent Account Number) of the investor - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun pan(): Optional = pan.getOptional("pan") - - /** - * Postal code of the investor's address - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun pincode(): Optional = pincode.getOptional("pincode") - - /** - * Returns the raw JSON value of [address]. - * - * Unlike [address], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("address") @ExcludeMissing fun _address(): JsonField = address + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - /** - * Returns the raw JSON value of [casId]. - * - * Unlike [casId], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("cas_id") @ExcludeMissing fun _casId(): JsonField = casId + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - /** - * Returns the raw JSON value of [email]. - * - * Unlike [email], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("email") @ExcludeMissing fun _email(): JsonField = email + /** + * Returns an immutable instance of [Equity]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Equity = + Equity( + additionalInfo, + isin, + name, + (transactions ?: JsonMissing.of()).map { it.toImmutable() }, + units, + value, + additionalProperties.toMutableMap(), + ) + } - /** - * Returns the raw JSON value of [mobile]. - * - * Unlike [mobile], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("mobile") @ExcludeMissing fun _mobile(): JsonField = mobile + private var validated: Boolean = false - /** - * Returns the raw JSON value of [name]. - * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + fun validate(): Equity = apply { + if (validated) { + return@apply + } - /** - * Returns the raw JSON value of [pan]. - * - * Unlike [pan], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("pan") @ExcludeMissing fun _pan(): JsonField = pan + additionalInfo().ifPresent { it.validate() } + isin() + name() + transactions().ifPresent { it.forEach { it.validate() } } + units() + value() + validated = true + } - /** - * Returns the raw JSON value of [pincode]. - * - * Unlike [pincode], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("pincode") @ExcludeMissing fun _pincode(): JsonField = pincode + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (isin.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (transactions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (units.asKnown().isPresent) 1 else 0) + + (if (value.asKnown().isPresent) 1 else 0) - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + /** Additional information specific to the equity */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val closeUnits: JsonField, + private val openUnits: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("close_units") + @ExcludeMissing + closeUnits: JsonField = JsonMissing.of(), + @JsonProperty("open_units") + @ExcludeMissing + openUnits: JsonField = JsonMissing.of(), + ) : this(closeUnits, openUnits, mutableMapOf()) - fun toBuilder() = Builder().from(this) + /** + * Closing balance units for the statement period (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun closeUnits(): Optional = closeUnits.getOptional("close_units") - companion object { + /** + * Opening balance units for the statement period (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun openUnits(): Optional = openUnits.getOptional("open_units") - /** Returns a mutable builder for constructing an instance of [Investor]. */ - @JvmStatic fun builder() = Builder() - } + /** + * Returns the raw JSON value of [closeUnits]. + * + * Unlike [closeUnits], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("close_units") + @ExcludeMissing + fun _closeUnits(): JsonField = closeUnits - /** A builder for [Investor]. */ - class Builder internal constructor() { + /** + * Returns the raw JSON value of [openUnits]. + * + * Unlike [openUnits], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("open_units") + @ExcludeMissing + fun _openUnits(): JsonField = openUnits - private var address: JsonField = JsonMissing.of() - private var casId: JsonField = JsonMissing.of() - private var email: JsonField = JsonMissing.of() - private var mobile: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var pan: JsonField = JsonMissing.of() - private var pincode: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - @JvmSynthetic - internal fun from(investor: Investor) = apply { - address = investor.address - casId = investor.casId - email = investor.email - mobile = investor.mobile - name = investor.name - pan = investor.pan - pincode = investor.pincode - additionalProperties = investor.additionalProperties.toMutableMap() - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - /** Address of the investor */ - fun address(address: String) = address(JsonField.of(address)) + fun toBuilder() = Builder().from(this) - /** - * Sets [Builder.address] to an arbitrary JSON value. - * - * You should usually call [Builder.address] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun address(address: JsonField) = apply { this.address = address } + companion object { - /** CAS ID of the investor (only for NSDL and CDSL) */ - fun casId(casId: String) = casId(JsonField.of(casId)) + /** + * Returns a mutable builder for constructing an instance of + * [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } - /** - * Sets [Builder.casId] to an arbitrary JSON value. - * - * You should usually call [Builder.casId] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun casId(casId: JsonField) = apply { this.casId = casId } + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { - /** Email address of the investor */ - fun email(email: String) = email(JsonField.of(email)) + private var closeUnits: JsonField = JsonMissing.of() + private var openUnits: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() - /** - * Sets [Builder.email] to an arbitrary JSON value. - * - * You should usually call [Builder.email] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun email(email: JsonField) = apply { this.email = email } + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + closeUnits = additionalInfo.closeUnits + openUnits = additionalInfo.openUnits + additionalProperties = + additionalInfo.additionalProperties.toMutableMap() + } - /** Mobile number of the investor */ - fun mobile(mobile: String) = mobile(JsonField.of(mobile)) + /** Closing balance units for the statement period (beta) */ + fun closeUnits(closeUnits: Float?) = + closeUnits(JsonField.ofNullable(closeUnits)) + + /** + * Alias for [Builder.closeUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun closeUnits(closeUnits: Float) = closeUnits(closeUnits as Float?) + + /** + * Alias for calling [Builder.closeUnits] with `closeUnits.orElse(null)`. + */ + fun closeUnits(closeUnits: Optional) = + closeUnits(closeUnits.getOrNull()) + + /** + * Sets [Builder.closeUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.closeUnits] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun closeUnits(closeUnits: JsonField) = apply { + this.closeUnits = closeUnits + } - /** - * Sets [Builder.mobile] to an arbitrary JSON value. - * - * You should usually call [Builder.mobile] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun mobile(mobile: JsonField) = apply { this.mobile = mobile } + /** Opening balance units for the statement period (beta) */ + fun openUnits(openUnits: Float?) = + openUnits(JsonField.ofNullable(openUnits)) + + /** + * Alias for [Builder.openUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun openUnits(openUnits: Float) = openUnits(openUnits as Float?) + + /** Alias for calling [Builder.openUnits] with `openUnits.orElse(null)`. */ + fun openUnits(openUnits: Optional) = openUnits(openUnits.getOrNull()) + + /** + * Sets [Builder.openUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.openUnits] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun openUnits(openUnits: JsonField) = apply { + this.openUnits = openUnits + } - /** Name of the investor */ - fun name(name: String) = name(JsonField.of(name)) + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - /** - * Sets [Builder.name] to an arbitrary JSON value. - * - * You should usually call [Builder.name] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun name(name: JsonField) = apply { this.name = name } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - /** PAN (Permanent Account Number) of the investor */ - fun pan(pan: String) = pan(JsonField.of(pan)) + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } - /** - * Sets [Builder.pan] to an arbitrary JSON value. - * - * You should usually call [Builder.pan] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun pan(pan: JsonField) = apply { this.pan = pan } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - /** Postal code of the investor's address */ - fun pincode(pincode: String) = pincode(JsonField.of(pincode)) + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - /** - * Sets [Builder.pincode] to an arbitrary JSON value. - * - * You should usually call [Builder.pincode] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun pincode(pincode: JsonField) = apply { this.pincode = pincode } + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + closeUnits, + openUnits, + additionalProperties.toMutableMap(), + ) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + private var validated: Boolean = false - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + closeUnits() + openUnits() + validated = true + } - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (closeUnits.asKnown().isPresent) 1 else 0) + + (if (openUnits.asKnown().isPresent) 1 else 0) - /** - * Returns an immutable instance of [Investor]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Investor = - Investor( - address, - casId, - email, - mobile, - name, - pan, - pincode, - additionalProperties.toMutableMap(), - ) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - private var validated: Boolean = false + return other is AdditionalInfo && + closeUnits == other.closeUnits && + openUnits == other.openUnits && + additionalProperties == other.additionalProperties + } - fun validate(): Investor = apply { - if (validated) { - return@apply - } + private val hashCode: Int by lazy { + Objects.hash(closeUnits, openUnits, additionalProperties) + } - address() - casId() - email() - mobile() - name() - pan() - pincode() - validated = true - } + override fun hashCode(): Int = hashCode - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + override fun toString() = + "AdditionalInfo{closeUnits=$closeUnits, openUnits=$openUnits, additionalProperties=$additionalProperties}" + } - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (address.asKnown().isPresent) 1 else 0) + - (if (casId.asKnown().isPresent) 1 else 0) + - (if (email.asKnown().isPresent) 1 else 0) + - (if (mobile.asKnown().isPresent) 1 else 0) + - (if (name.asKnown().isPresent) 1 else 0) + - (if (pan.asKnown().isPresent) 1 else 0) + - (if (pincode.asKnown().isPresent) 1 else 0) + /** + * Unified transaction schema for all holding types (MF folios, equities, bonds, + * etc.) + */ + class Transaction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, + private val amount: JsonField, + private val balance: JsonField, + private val date: JsonField, + private val description: JsonField, + private val dividendRate: JsonField, + private val nav: JsonField, + private val type: JsonField, + private val units: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("amount") + @ExcludeMissing + amount: JsonField = JsonMissing.of(), + @JsonProperty("balance") + @ExcludeMissing + balance: JsonField = JsonMissing.of(), + @JsonProperty("date") + @ExcludeMissing + date: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("dividend_rate") + @ExcludeMissing + dividendRate: JsonField = JsonMissing.of(), + @JsonProperty("nav") + @ExcludeMissing + nav: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + @JsonProperty("units") + @ExcludeMissing + units: JsonField = JsonMissing.of(), + ) : this( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + mutableMapOf(), + ) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Additional transaction-specific fields that vary by source + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") - return other is Investor && - address == other.address && - casId == other.casId && - email == other.email && - mobile == other.mobile && - name == other.name && - pan == other.pan && - pincode == other.pincode && - additionalProperties == other.additionalProperties - } + /** + * Transaction amount in currency (computed from units × price/NAV) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun amount(): Optional = amount.getOptional("amount") - private val hashCode: Int by lazy { - Objects.hash(address, casId, email, mobile, name, pan, pincode, additionalProperties) - } + /** + * Balance units after transaction + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun balance(): Optional = balance.getOptional("balance") - override fun hashCode(): Int = hashCode + /** + * Transaction date (YYYY-MM-DD) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun date(): Optional = date.getOptional("date") - override fun toString() = - "Investor{address=$address, casId=$casId, email=$email, mobile=$mobile, name=$name, pan=$pan, pincode=$pincode, additionalProperties=$additionalProperties}" - } + /** + * Transaction description/particulars + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun description(): Optional = description.getOptional("description") - class Meta - private constructor( - private val casType: JsonField, - private val generatedAt: JsonField, - private val statementPeriod: JsonField, - private val additionalProperties: MutableMap, - ) { + /** + * Dividend rate (for DIVIDEND_PAYOUT transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun dividendRate(): Optional = dividendRate.getOptional("dividend_rate") - @JsonCreator - private constructor( - @JsonProperty("cas_type") - @ExcludeMissing - casType: JsonField = JsonMissing.of(), - @JsonProperty("generated_at") - @ExcludeMissing - generatedAt: JsonField = JsonMissing.of(), - @JsonProperty("statement_period") - @ExcludeMissing - statementPeriod: JsonField = JsonMissing.of(), - ) : this(casType, generatedAt, statementPeriod, mutableMapOf()) + /** + * NAV/price per unit on transaction date + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun nav(): Optional = nav.getOptional("nav") - /** - * Type of CAS detected and processed - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun casType(): Optional = casType.getOptional("cas_type") + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, + * REVERSAL, UNKNOWN. + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") - /** - * Timestamp when the response was generated - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun generatedAt(): Optional = generatedAt.getOptional("generated_at") + /** + * Number of units involved in transaction + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun units(): Optional = units.getOptional("units") - /** - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun statementPeriod(): Optional = - statementPeriod.getOptional("statement_period") + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo - /** - * Returns the raw JSON value of [casType]. - * - * Unlike [casType], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("cas_type") @ExcludeMissing fun _casType(): JsonField = casType + /** + * Returns the raw JSON value of [amount]. + * + * Unlike [amount], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("amount") @ExcludeMissing fun _amount(): JsonField = amount - /** - * Returns the raw JSON value of [generatedAt]. - * - * Unlike [generatedAt], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("generated_at") - @ExcludeMissing - fun _generatedAt(): JsonField = generatedAt + /** + * Returns the raw JSON value of [balance]. + * + * Unlike [balance], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("balance") + @ExcludeMissing + fun _balance(): JsonField = balance - /** - * Returns the raw JSON value of [statementPeriod]. - * - * Unlike [statementPeriod], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("statement_period") - @ExcludeMissing - fun _statementPeriod(): JsonField = statementPeriod + /** + * Returns the raw JSON value of [date]. + * + * Unlike [date], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("date") @ExcludeMissing fun _date(): JsonField = date - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + /** + * Returns the raw JSON value of [dividendRate]. + * + * Unlike [dividendRate], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("dividend_rate") + @ExcludeMissing + fun _dividendRate(): JsonField = dividendRate - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [nav]. + * + * Unlike [nav], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("nav") @ExcludeMissing fun _nav(): JsonField = nav - companion object { + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type - /** Returns a mutable builder for constructing an instance of [Meta]. */ - @JvmStatic fun builder() = Builder() - } + /** + * Returns the raw JSON value of [units]. + * + * Unlike [units], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units - /** A builder for [Meta]. */ - class Builder internal constructor() { + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - private var casType: JsonField = JsonMissing.of() - private var generatedAt: JsonField = JsonMissing.of() - private var statementPeriod: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - @JvmSynthetic - internal fun from(meta: Meta) = apply { - casType = meta.casType - generatedAt = meta.generatedAt - statementPeriod = meta.statementPeriod - additionalProperties = meta.additionalProperties.toMutableMap() - } + fun toBuilder() = Builder().from(this) - /** Type of CAS detected and processed */ - fun casType(casType: CasType) = casType(JsonField.of(casType)) + companion object { - /** - * Sets [Builder.casType] to an arbitrary JSON value. - * - * You should usually call [Builder.casType] with a well-typed [CasType] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun casType(casType: JsonField) = apply { this.casType = casType } + /** + * Returns a mutable builder for constructing an instance of [Transaction]. + */ + @JvmStatic fun builder() = Builder() + } - /** Timestamp when the response was generated */ - fun generatedAt(generatedAt: OffsetDateTime) = generatedAt(JsonField.of(generatedAt)) + /** A builder for [Transaction]. */ + class Builder internal constructor() { + + private var additionalInfo: JsonField = JsonMissing.of() + private var amount: JsonField = JsonMissing.of() + private var balance: JsonField = JsonMissing.of() + private var date: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var dividendRate: JsonField = JsonMissing.of() + private var nav: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var units: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(transaction: Transaction) = apply { + additionalInfo = transaction.additionalInfo + amount = transaction.amount + balance = transaction.balance + date = transaction.date + description = transaction.description + dividendRate = transaction.dividendRate + nav = transaction.nav + type = transaction.type + units = transaction.units + additionalProperties = transaction.additionalProperties.toMutableMap() + } - /** - * Sets [Builder.generatedAt] to an arbitrary JSON value. - * - * You should usually call [Builder.generatedAt] with a well-typed [OffsetDateTime] - * value instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun generatedAt(generatedAt: JsonField) = apply { - this.generatedAt = generatedAt - } + /** Additional transaction-specific fields that vary by source */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) + + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { + this.additionalInfo = additionalInfo + } - fun statementPeriod(statementPeriod: StatementPeriod) = - statementPeriod(JsonField.of(statementPeriod)) + /** Transaction amount in currency (computed from units × price/NAV) */ + fun amount(amount: Float?) = amount(JsonField.ofNullable(amount)) + + /** + * Alias for [Builder.amount]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun amount(amount: Float) = amount(amount as Float?) + + /** Alias for calling [Builder.amount] with `amount.orElse(null)`. */ + fun amount(amount: Optional) = amount(amount.getOrNull()) + + /** + * Sets [Builder.amount] to an arbitrary JSON value. + * + * You should usually call [Builder.amount] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun amount(amount: JsonField) = apply { this.amount = amount } + + /** Balance units after transaction */ + fun balance(balance: Float) = balance(JsonField.of(balance)) + + /** + * Sets [Builder.balance] to an arbitrary JSON value. + * + * You should usually call [Builder.balance] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun balance(balance: JsonField) = apply { this.balance = balance } + + /** Transaction date (YYYY-MM-DD) */ + fun date(date: LocalDate) = date(JsonField.of(date)) + + /** + * Sets [Builder.date] to an arbitrary JSON value. + * + * You should usually call [Builder.date] with a well-typed [LocalDate] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun date(date: JsonField) = apply { this.date = date } + + /** Transaction description/particulars */ + fun description(description: String) = + description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } - /** - * Sets [Builder.statementPeriod] to an arbitrary JSON value. - * - * You should usually call [Builder.statementPeriod] with a well-typed [StatementPeriod] - * value instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun statementPeriod(statementPeriod: JsonField) = apply { - this.statementPeriod = statementPeriod - } + /** Dividend rate (for DIVIDEND_PAYOUT transactions) */ + fun dividendRate(dividendRate: Float?) = + dividendRate(JsonField.ofNullable(dividendRate)) + + /** + * Alias for [Builder.dividendRate]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun dividendRate(dividendRate: Float) = dividendRate(dividendRate as Float?) + + /** + * Alias for calling [Builder.dividendRate] with + * `dividendRate.orElse(null)`. + */ + fun dividendRate(dividendRate: Optional) = + dividendRate(dividendRate.getOrNull()) + + /** + * Sets [Builder.dividendRate] to an arbitrary JSON value. + * + * You should usually call [Builder.dividendRate] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun dividendRate(dividendRate: JsonField) = apply { + this.dividendRate = dividendRate + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** NAV/price per unit on transaction date */ + fun nav(nav: Float?) = nav(JsonField.ofNullable(nav)) + + /** + * Alias for [Builder.nav]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun nav(nav: Float) = nav(nav as Float?) + + /** Alias for calling [Builder.nav] with `nav.orElse(null)`. */ + fun nav(nav: Optional) = nav(nav.getOrNull()) + + /** + * Sets [Builder.nav] to an arbitrary JSON value. + * + * You should usually call [Builder.nav] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun nav(nav: JsonField) = apply { this.nav = nav } + + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, + * DIVIDEND_PAYOUT, DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, + * STT_TAX, MISC, REVERSAL, UNKNOWN. + */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + /** Number of units involved in transaction */ + fun units(units: Float) = units(JsonField.of(units)) + + /** + * Sets [Builder.units] to an arbitrary JSON value. + * + * You should usually call [Builder.units] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun units(units: JsonField) = apply { this.units = units } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + /** + * Returns an immutable instance of [Transaction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Transaction = + Transaction( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + additionalProperties.toMutableMap(), + ) + } - /** - * Returns an immutable instance of [Meta]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Meta = - Meta(casType, generatedAt, statementPeriod, additionalProperties.toMutableMap()) - } + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): Transaction = apply { + if (validated) { + return@apply + } - fun validate(): Meta = apply { - if (validated) { - return@apply - } + additionalInfo().ifPresent { it.validate() } + amount() + balance() + date() + description() + dividendRate() + nav() + type().ifPresent { it.validate() } + units() + validated = true + } - casType().ifPresent { it.validate() } - generatedAt() - statementPeriod().ifPresent { it.validate() } - validated = true - } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (amount.asKnown().isPresent) 1 else 0) + + (if (balance.asKnown().isPresent) 1 else 0) + + (if (date.asKnown().isPresent) 1 else 0) + + (if (description.asKnown().isPresent) 1 else 0) + + (if (dividendRate.asKnown().isPresent) 1 else 0) + + (if (nav.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (units.asKnown().isPresent) 1 else 0) + + /** Additional transaction-specific fields that vary by source */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val capitalWithdrawal: JsonField, + private val credit: JsonField, + private val debit: JsonField, + private val incomeDistribution: JsonField, + private val orderNo: JsonField, + private val price: JsonField, + private val stampDuty: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("capital_withdrawal") + @ExcludeMissing + capitalWithdrawal: JsonField = JsonMissing.of(), + @JsonProperty("credit") + @ExcludeMissing + credit: JsonField = JsonMissing.of(), + @JsonProperty("debit") + @ExcludeMissing + debit: JsonField = JsonMissing.of(), + @JsonProperty("income_distribution") + @ExcludeMissing + incomeDistribution: JsonField = JsonMissing.of(), + @JsonProperty("order_no") + @ExcludeMissing + orderNo: JsonField = JsonMissing.of(), + @JsonProperty("price") + @ExcludeMissing + price: JsonField = JsonMissing.of(), + @JsonProperty("stamp_duty") + @ExcludeMissing + stampDuty: JsonField = JsonMissing.of(), + ) : this( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + mutableMapOf(), + ) - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (casType.asKnown().getOrNull()?.validity() ?: 0) + - (if (generatedAt.asKnown().isPresent) 1 else 0) + - (statementPeriod.asKnown().getOrNull()?.validity() ?: 0) + /** + * Capital withdrawal amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun capitalWithdrawal(): Optional = + capitalWithdrawal.getOptional("capital_withdrawal") + + /** + * Units credited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun credit(): Optional = credit.getOptional("credit") + + /** + * Units debited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun debit(): Optional = debit.getOptional("debit") + + /** + * Income distribution amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun incomeDistribution(): Optional = + incomeDistribution.getOptional("income_distribution") + + /** + * Order/transaction reference number (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun orderNo(): Optional = orderNo.getOptional("order_no") + + /** + * Price per unit (NSDL/CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun price(): Optional = price.getOptional("price") + + /** + * Stamp duty charged + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun stampDuty(): Optional = stampDuty.getOptional("stamp_duty") + + /** + * Returns the raw JSON value of [capitalWithdrawal]. + * + * Unlike [capitalWithdrawal], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("capital_withdrawal") + @ExcludeMissing + fun _capitalWithdrawal(): JsonField = capitalWithdrawal + + /** + * Returns the raw JSON value of [credit]. + * + * Unlike [credit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("credit") + @ExcludeMissing + fun _credit(): JsonField = credit + + /** + * Returns the raw JSON value of [debit]. + * + * Unlike [debit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("debit") + @ExcludeMissing + fun _debit(): JsonField = debit + + /** + * Returns the raw JSON value of [incomeDistribution]. + * + * Unlike [incomeDistribution], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("income_distribution") + @ExcludeMissing + fun _incomeDistribution(): JsonField = incomeDistribution + + /** + * Returns the raw JSON value of [orderNo]. + * + * Unlike [orderNo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("order_no") + @ExcludeMissing + fun _orderNo(): JsonField = orderNo + + /** + * Returns the raw JSON value of [price]. + * + * Unlike [price], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("price") + @ExcludeMissing + fun _price(): JsonField = price + + /** + * Returns the raw JSON value of [stampDuty]. + * + * Unlike [stampDuty], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("stamp_duty") + @ExcludeMissing + fun _stampDuty(): JsonField = stampDuty + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - /** Type of CAS detected and processed */ - class CasType @JsonCreator private constructor(private val value: JsonField) : - Enum { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known 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. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun toBuilder() = Builder().from(this) - companion object { + companion object { - @JvmField val NSDL = of("NSDL") + /** + * Returns a mutable builder for constructing an instance of + * [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } - @JvmField val CDSL = of("CDSL") + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { + + private var capitalWithdrawal: JsonField = JsonMissing.of() + private var credit: JsonField = JsonMissing.of() + private var debit: JsonField = JsonMissing.of() + private var incomeDistribution: JsonField = JsonMissing.of() + private var orderNo: JsonField = JsonMissing.of() + private var price: JsonField = JsonMissing.of() + private var stampDuty: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + capitalWithdrawal = additionalInfo.capitalWithdrawal + credit = additionalInfo.credit + debit = additionalInfo.debit + incomeDistribution = additionalInfo.incomeDistribution + orderNo = additionalInfo.orderNo + price = additionalInfo.price + stampDuty = additionalInfo.stampDuty + additionalProperties = + additionalInfo.additionalProperties.toMutableMap() + } + + /** Capital withdrawal amount (CDSL MF transactions) */ + fun capitalWithdrawal(capitalWithdrawal: Float) = + capitalWithdrawal(JsonField.of(capitalWithdrawal)) + + /** + * Sets [Builder.capitalWithdrawal] to an arbitrary JSON value. + * + * You should usually call [Builder.capitalWithdrawal] with a well-typed + * [Float] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun capitalWithdrawal(capitalWithdrawal: JsonField) = apply { + this.capitalWithdrawal = capitalWithdrawal + } + + /** Units credited (demat transactions) */ + fun credit(credit: Float) = credit(JsonField.of(credit)) + + /** + * Sets [Builder.credit] to an arbitrary JSON value. + * + * You should usually call [Builder.credit] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun credit(credit: JsonField) = apply { this.credit = credit } + + /** Units debited (demat transactions) */ + fun debit(debit: Float) = debit(JsonField.of(debit)) + + /** + * Sets [Builder.debit] to an arbitrary JSON value. + * + * You should usually call [Builder.debit] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun debit(debit: JsonField) = apply { this.debit = debit } + + /** Income distribution amount (CDSL MF transactions) */ + fun incomeDistribution(incomeDistribution: Float) = + incomeDistribution(JsonField.of(incomeDistribution)) + + /** + * Sets [Builder.incomeDistribution] to an arbitrary JSON value. + * + * You should usually call [Builder.incomeDistribution] with a + * well-typed [Float] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun incomeDistribution(incomeDistribution: JsonField) = apply { + this.incomeDistribution = incomeDistribution + } + + /** Order/transaction reference number (demat transactions) */ + fun orderNo(orderNo: String) = orderNo(JsonField.of(orderNo)) + + /** + * Sets [Builder.orderNo] to an arbitrary JSON value. + * + * You should usually call [Builder.orderNo] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun orderNo(orderNo: JsonField) = apply { + this.orderNo = orderNo + } + + /** Price per unit (NSDL/CDSL MF transactions) */ + fun price(price: Float) = price(JsonField.of(price)) + + /** + * Sets [Builder.price] to an arbitrary JSON value. + * + * You should usually call [Builder.price] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun price(price: JsonField) = apply { this.price = price } + + /** Stamp duty charged */ + fun stampDuty(stampDuty: Float) = stampDuty(JsonField.of(stampDuty)) + + /** + * Sets [Builder.stampDuty] to an arbitrary JSON value. + * + * You should usually call [Builder.stampDuty] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun stampDuty(stampDuty: JsonField) = apply { + this.stampDuty = stampDuty + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties.toMutableMap(), + ) + } - @JvmField val CAMS_KFINTECH = of("CAMS_KFINTECH") + private var validated: Boolean = false + + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } + + capitalWithdrawal() + credit() + debit() + incomeDistribution() + orderNo() + price() + stampDuty() + validated = true + } - @JvmStatic fun of(value: String) = CasType(JsonField.of(value)) - } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (capitalWithdrawal.asKnown().isPresent) 1 else 0) + + (if (credit.asKnown().isPresent) 1 else 0) + + (if (debit.asKnown().isPresent) 1 else 0) + + (if (incomeDistribution.asKnown().isPresent) 1 else 0) + + (if (orderNo.asKnown().isPresent) 1 else 0) + + (if (price.asKnown().isPresent) 1 else 0) + + (if (stampDuty.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AdditionalInfo && + capitalWithdrawal == other.capitalWithdrawal && + credit == other.credit && + debit == other.debit && + incomeDistribution == other.incomeDistribution && + orderNo == other.orderNo && + price == other.price && + stampDuty == other.stampDuty && + additionalProperties == other.additionalProperties + } - /** An enum containing [CasType]'s known values. */ - enum class Known { - NSDL, - CDSL, - CAMS_KFINTECH, - } + private val hashCode: Int by lazy { + Objects.hash( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties, + ) + } - /** - * An enum containing [CasType]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [CasType] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. 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. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - NSDL, - CDSL, - CAMS_KFINTECH, - /** - * An enum member indicating that [CasType] was instantiated with an unknown value. - */ - _UNKNOWN, - } + override fun hashCode(): Int = hashCode - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you - * want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - NSDL -> Value.NSDL - CDSL -> Value.CDSL - CAMS_KFINTECH -> Value.CAMS_KFINTECH - else -> Value._UNKNOWN - } + override fun toString() = + "AdditionalInfo{capitalWithdrawal=$capitalWithdrawal, credit=$credit, debit=$debit, incomeDistribution=$incomeDistribution, orderNo=$orderNo, price=$price, stampDuty=$stampDuty, additionalProperties=$additionalProperties}" + } - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and - * don't want to throw for the unknown case. - * - * @throws CasParserInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - NSDL -> Known.NSDL - CDSL -> Known.CDSL - CAMS_KFINTECH -> Known.CAMS_KFINTECH - else -> throw CasParserInvalidDataException("Unknown CasType: $value") - } + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, + * REVERSAL, UNKNOWN. + */ + class Type + @JsonCreator + private constructor(private val value: JsonField) : Enum { - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws CasParserInvalidDataException if this class instance's value does not have - * the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - CasParserInvalidDataException("Value is not a String") - } + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data + * that doesn't match any known 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. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value - private var validated: Boolean = false + companion object { - fun validate(): CasType = apply { - if (validated) { - return@apply - } + @JvmField val PURCHASE = of("PURCHASE") - known() - validated = true - } + @JvmField val PURCHASE_SIP = of("PURCHASE_SIP") - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + @JvmField val REDEMPTION = of("REDEMPTION") - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + @JvmField val SWITCH_IN = of("SWITCH_IN") - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + @JvmField val SWITCH_IN_MERGER = of("SWITCH_IN_MERGER") - return other is CasType && value == other.value - } + @JvmField val SWITCH_OUT = of("SWITCH_OUT") - override fun hashCode() = value.hashCode() + @JvmField val SWITCH_OUT_MERGER = of("SWITCH_OUT_MERGER") - override fun toString() = value.toString() - } + @JvmField val DIVIDEND_PAYOUT = of("DIVIDEND_PAYOUT") - class StatementPeriod - private constructor( - private val from: JsonField, - private val to: JsonField, - private val additionalProperties: MutableMap, - ) { + @JvmField val DIVIDEND_REINVEST = of("DIVIDEND_REINVEST") - @JsonCreator - private constructor( - @JsonProperty("from") @ExcludeMissing from: JsonField = JsonMissing.of(), - @JsonProperty("to") @ExcludeMissing to: JsonField = JsonMissing.of(), - ) : this(from, to, mutableMapOf()) + @JvmField val SEGREGATION = of("SEGREGATION") - /** - * Start date of the statement period - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun from(): Optional = from.getOptional("from") + @JvmField val STAMP_DUTY_TAX = of("STAMP_DUTY_TAX") - /** - * End date of the statement period - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun to(): Optional = to.getOptional("to") + @JvmField val TDS_TAX = of("TDS_TAX") - /** - * Returns the raw JSON value of [from]. - * - * Unlike [from], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("from") @ExcludeMissing fun _from(): JsonField = from + @JvmField val STT_TAX = of("STT_TAX") - /** - * Returns the raw JSON value of [to]. - * - * Unlike [to], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("to") @ExcludeMissing fun _to(): JsonField = to + @JvmField val MISC = of("MISC") - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + @JvmField val REVERSAL = of("REVERSAL") - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + @JvmField val UNKNOWN = of("UNKNOWN") - fun toBuilder() = Builder().from(this) + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } - companion object { + /** An enum containing [Type]'s known values. */ + enum class Known { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + } - /** Returns a mutable builder for constructing an instance of [StatementPeriod]. */ - @JvmStatic fun builder() = Builder() - } + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. 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. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + /** + * An enum member indicating that [Type] was instantiated with an + * unknown value. + */ + _UNKNOWN, + } - /** A builder for [StatementPeriod]. */ - class Builder internal constructor() { + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always + * known or if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + PURCHASE -> Value.PURCHASE + PURCHASE_SIP -> Value.PURCHASE_SIP + REDEMPTION -> Value.REDEMPTION + SWITCH_IN -> Value.SWITCH_IN + SWITCH_IN_MERGER -> Value.SWITCH_IN_MERGER + SWITCH_OUT -> Value.SWITCH_OUT + SWITCH_OUT_MERGER -> Value.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Value.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Value.DIVIDEND_REINVEST + SEGREGATION -> Value.SEGREGATION + STAMP_DUTY_TAX -> Value.STAMP_DUTY_TAX + TDS_TAX -> Value.TDS_TAX + STT_TAX -> Value.STT_TAX + MISC -> Value.MISC + REVERSAL -> Value.REVERSAL + UNKNOWN -> Value.UNKNOWN + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always + * known and don't want to throw for the unknown case. + * + * @throws CasParserInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + PURCHASE -> Known.PURCHASE + PURCHASE_SIP -> Known.PURCHASE_SIP + REDEMPTION -> Known.REDEMPTION + SWITCH_IN -> Known.SWITCH_IN + SWITCH_IN_MERGER -> Known.SWITCH_IN_MERGER + SWITCH_OUT -> Known.SWITCH_OUT + SWITCH_OUT_MERGER -> Known.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Known.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Known.DIVIDEND_REINVEST + SEGREGATION -> Known.SEGREGATION + STAMP_DUTY_TAX -> Known.STAMP_DUTY_TAX + TDS_TAX -> Known.TDS_TAX + STT_TAX -> Known.STT_TAX + MISC -> Known.MISC + REVERSAL -> Known.REVERSAL + UNKNOWN -> Known.UNKNOWN + else -> throw CasParserInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily + * for debugging and generally doesn't throw. + * + * @throws CasParserInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + CasParserInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } - private var from: JsonField = JsonMissing.of() - private var to: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } - @JvmSynthetic - internal fun from(statementPeriod: StatementPeriod) = apply { - from = statementPeriod.from - to = statementPeriod.to - additionalProperties = statementPeriod.additionalProperties.toMutableMap() - } + override fun hashCode() = value.hashCode() - /** Start date of the statement period */ - fun from(from: LocalDate) = from(JsonField.of(from)) + override fun toString() = value.toString() + } - /** - * Sets [Builder.from] to an arbitrary JSON value. - * - * You should usually call [Builder.from] with a well-typed [LocalDate] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun from(from: JsonField) = apply { this.from = from } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - /** End date of the statement period */ - fun to(to: LocalDate) = to(JsonField.of(to)) + return other is Transaction && + additionalInfo == other.additionalInfo && + amount == other.amount && + balance == other.balance && + date == other.date && + description == other.description && + dividendRate == other.dividendRate && + nav == other.nav && + type == other.type && + units == other.units && + additionalProperties == other.additionalProperties + } - /** - * Sets [Builder.to] to an arbitrary JSON value. - * - * You should usually call [Builder.to] with a well-typed [LocalDate] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun to(to: JsonField) = apply { this.to = to } + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + additionalProperties, + ) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + override fun hashCode(): Int = hashCode - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) + override fun toString() = + "Transaction{additionalInfo=$additionalInfo, amount=$amount, balance=$balance, date=$date, description=$description, dividendRate=$dividendRate, nav=$nav, type=$type, units=$units, additionalProperties=$additionalProperties}" } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) + return other is Equity && + additionalInfo == other.additionalInfo && + isin == other.isin && + name == other.name && + transactions == other.transactions && + units == other.units && + value == other.value && + additionalProperties == other.additionalProperties } - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + isin, + name, + transactions, + units, + value, + additionalProperties, + ) } - /** - * Returns an immutable instance of [StatementPeriod]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): StatementPeriod = - StatementPeriod(from, to, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): StatementPeriod = apply { - if (validated) { - return@apply - } + override fun hashCode(): Int = hashCode - from() - to() - validated = true + override fun toString() = + "Equity{additionalInfo=$additionalInfo, isin=$isin, name=$name, transactions=$transactions, units=$units, value=$value, additionalProperties=$additionalProperties}" } - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + class GovernmentSecurity + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, + private val isin: JsonField, + private val name: JsonField, + private val transactions: JsonField>, + private val units: JsonField, + private val value: JsonField, + private val additionalProperties: MutableMap, + ) { - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (from.asKnown().isPresent) 1 else 0) + (if (to.asKnown().isPresent) 1 else 0) + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("isin") + @ExcludeMissing + isin: JsonField = JsonMissing.of(), + @JsonProperty("name") + @ExcludeMissing + name: JsonField = JsonMissing.of(), + @JsonProperty("transactions") + @ExcludeMissing + transactions: JsonField> = JsonMissing.of(), + @JsonProperty("units") + @ExcludeMissing + units: JsonField = JsonMissing.of(), + @JsonProperty("value") + @ExcludeMissing + value: JsonField = JsonMissing.of(), + ) : this(additionalInfo, isin, name, transactions, units, value, mutableMapOf()) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Additional information specific to the government security + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") - return other is StatementPeriod && - from == other.from && - to == other.to && - additionalProperties == other.additionalProperties - } + /** + * ISIN code of the government security + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun isin(): Optional = isin.getOptional("isin") - private val hashCode: Int by lazy { Objects.hash(from, to, additionalProperties) } + /** + * Name of the government security + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") - override fun hashCode(): Int = hashCode + /** + * List of transactions for this holding (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun transactions(): Optional> = + transactions.getOptional("transactions") - override fun toString() = - "StatementPeriod{from=$from, to=$to, additionalProperties=$additionalProperties}" - } + /** + * Number of units held + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun units(): Optional = units.getOptional("units") - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Current market value of the holding + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun value(): Optional = value.getOptional("value") - return other is Meta && - casType == other.casType && - generatedAt == other.generatedAt && - statementPeriod == other.statementPeriod && - additionalProperties == other.additionalProperties - } + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo - private val hashCode: Int by lazy { - Objects.hash(casType, generatedAt, statementPeriod, additionalProperties) - } + /** + * Returns the raw JSON value of [isin]. + * + * Unlike [isin], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("isin") @ExcludeMissing fun _isin(): JsonField = isin - override fun hashCode(): Int = hashCode + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - override fun toString() = - "Meta{casType=$casType, generatedAt=$generatedAt, statementPeriod=$statementPeriod, additionalProperties=$additionalProperties}" - } + /** + * Returns the raw JSON value of [transactions]. + * + * Unlike [transactions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("transactions") + @ExcludeMissing + fun _transactions(): JsonField> = transactions - class MutualFund - private constructor( - private val additionalInfo: JsonField, + /** + * Returns the raw JSON value of [units]. + * + * Unlike [units], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units + + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [GovernmentSecurity]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GovernmentSecurity]. */ + class Builder internal constructor() { + + private var additionalInfo: JsonField = JsonMissing.of() + private var isin: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var transactions: JsonField>? = null + private var units: JsonField = JsonMissing.of() + private var value: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(governmentSecurity: GovernmentSecurity) = apply { + additionalInfo = governmentSecurity.additionalInfo + isin = governmentSecurity.isin + name = governmentSecurity.name + transactions = governmentSecurity.transactions.map { it.toMutableList() } + units = governmentSecurity.units + value = governmentSecurity.value + additionalProperties = + governmentSecurity.additionalProperties.toMutableMap() + } + + /** Additional information specific to the government security */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) + + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { + this.additionalInfo = additionalInfo + } + + /** ISIN code of the government security */ + fun isin(isin: String) = isin(JsonField.of(isin)) + + /** + * Sets [Builder.isin] to an arbitrary JSON value. + * + * You should usually call [Builder.isin] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun isin(isin: JsonField) = apply { this.isin = isin } + + /** Name of the government security */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** List of transactions for this holding (beta) */ + fun transactions(transactions: List) = + transactions(JsonField.of(transactions)) + + /** + * Sets [Builder.transactions] to an arbitrary JSON value. + * + * You should usually call [Builder.transactions] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun transactions(transactions: JsonField>) = apply { + this.transactions = transactions.map { it.toMutableList() } + } + + /** + * Adds a single [Transaction] to [transactions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTransaction(transaction: Transaction) = apply { + transactions = + (transactions ?: JsonField.of(mutableListOf())).also { + checkKnown("transactions", it).add(transaction) + } + } + + /** Number of units held */ + fun units(units: Float) = units(JsonField.of(units)) + + /** + * Sets [Builder.units] to an arbitrary JSON value. + * + * You should usually call [Builder.units] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun units(units: JsonField) = apply { this.units = units } + + /** Current market value of the holding */ + fun value(value: Float) = value(JsonField.of(value)) + + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun value(value: JsonField) = apply { this.value = value } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [GovernmentSecurity]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): GovernmentSecurity = + GovernmentSecurity( + additionalInfo, + isin, + name, + (transactions ?: JsonMissing.of()).map { it.toImmutable() }, + units, + value, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): GovernmentSecurity = apply { + if (validated) { + return@apply + } + + additionalInfo().ifPresent { it.validate() } + isin() + name() + transactions().ifPresent { it.forEach { it.validate() } } + units() + value() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (isin.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (transactions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (units.asKnown().isPresent) 1 else 0) + + (if (value.asKnown().isPresent) 1 else 0) + + /** Additional information specific to the government security */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val closeUnits: JsonField, + private val openUnits: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("close_units") + @ExcludeMissing + closeUnits: JsonField = JsonMissing.of(), + @JsonProperty("open_units") + @ExcludeMissing + openUnits: JsonField = JsonMissing.of(), + ) : this(closeUnits, openUnits, mutableMapOf()) + + /** + * Closing balance units for the statement period (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun closeUnits(): Optional = closeUnits.getOptional("close_units") + + /** + * Opening balance units for the statement period (beta) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun openUnits(): Optional = openUnits.getOptional("open_units") + + /** + * Returns the raw JSON value of [closeUnits]. + * + * Unlike [closeUnits], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("close_units") + @ExcludeMissing + fun _closeUnits(): JsonField = closeUnits + + /** + * Returns the raw JSON value of [openUnits]. + * + * Unlike [openUnits], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("open_units") + @ExcludeMissing + fun _openUnits(): JsonField = openUnits + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { + + private var closeUnits: JsonField = JsonMissing.of() + private var openUnits: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + closeUnits = additionalInfo.closeUnits + openUnits = additionalInfo.openUnits + additionalProperties = + additionalInfo.additionalProperties.toMutableMap() + } + + /** Closing balance units for the statement period (beta) */ + fun closeUnits(closeUnits: Float?) = + closeUnits(JsonField.ofNullable(closeUnits)) + + /** + * Alias for [Builder.closeUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun closeUnits(closeUnits: Float) = closeUnits(closeUnits as Float?) + + /** + * Alias for calling [Builder.closeUnits] with `closeUnits.orElse(null)`. + */ + fun closeUnits(closeUnits: Optional) = + closeUnits(closeUnits.getOrNull()) + + /** + * Sets [Builder.closeUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.closeUnits] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun closeUnits(closeUnits: JsonField) = apply { + this.closeUnits = closeUnits + } + + /** Opening balance units for the statement period (beta) */ + fun openUnits(openUnits: Float?) = + openUnits(JsonField.ofNullable(openUnits)) + + /** + * Alias for [Builder.openUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun openUnits(openUnits: Float) = openUnits(openUnits as Float?) + + /** Alias for calling [Builder.openUnits] with `openUnits.orElse(null)`. */ + fun openUnits(openUnits: Optional) = openUnits(openUnits.getOrNull()) + + /** + * Sets [Builder.openUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.openUnits] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun openUnits(openUnits: JsonField) = apply { + this.openUnits = openUnits + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + closeUnits, + openUnits, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } + + closeUnits() + openUnits() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (closeUnits.asKnown().isPresent) 1 else 0) + + (if (openUnits.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AdditionalInfo && + closeUnits == other.closeUnits && + openUnits == other.openUnits && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(closeUnits, openUnits, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AdditionalInfo{closeUnits=$closeUnits, openUnits=$openUnits, additionalProperties=$additionalProperties}" + } + + /** + * Unified transaction schema for all holding types (MF folios, equities, bonds, + * etc.) + */ + class Transaction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, + private val amount: JsonField, + private val balance: JsonField, + private val date: JsonField, + private val description: JsonField, + private val dividendRate: JsonField, + private val nav: JsonField, + private val type: JsonField, + private val units: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("amount") + @ExcludeMissing + amount: JsonField = JsonMissing.of(), + @JsonProperty("balance") + @ExcludeMissing + balance: JsonField = JsonMissing.of(), + @JsonProperty("date") + @ExcludeMissing + date: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("dividend_rate") + @ExcludeMissing + dividendRate: JsonField = JsonMissing.of(), + @JsonProperty("nav") + @ExcludeMissing + nav: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + @JsonProperty("units") + @ExcludeMissing + units: JsonField = JsonMissing.of(), + ) : this( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + mutableMapOf(), + ) + + /** + * Additional transaction-specific fields that vary by source + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") + + /** + * Transaction amount in currency (computed from units × price/NAV) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun amount(): Optional = amount.getOptional("amount") + + /** + * Balance units after transaction + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun balance(): Optional = balance.getOptional("balance") + + /** + * Transaction date (YYYY-MM-DD) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun date(): Optional = date.getOptional("date") + + /** + * Transaction description/particulars + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun description(): Optional = description.getOptional("description") + + /** + * Dividend rate (for DIVIDEND_PAYOUT transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun dividendRate(): Optional = dividendRate.getOptional("dividend_rate") + + /** + * NAV/price per unit on transaction date + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun nav(): Optional = nav.getOptional("nav") + + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, + * REVERSAL, UNKNOWN. + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") + + /** + * Number of units involved in transaction + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun units(): Optional = units.getOptional("units") + + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo + + /** + * Returns the raw JSON value of [amount]. + * + * Unlike [amount], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("amount") @ExcludeMissing fun _amount(): JsonField = amount + + /** + * Returns the raw JSON value of [balance]. + * + * Unlike [balance], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("balance") + @ExcludeMissing + fun _balance(): JsonField = balance + + /** + * Returns the raw JSON value of [date]. + * + * Unlike [date], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("date") @ExcludeMissing fun _date(): JsonField = date + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description + + /** + * Returns the raw JSON value of [dividendRate]. + * + * Unlike [dividendRate], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("dividend_rate") + @ExcludeMissing + fun _dividendRate(): JsonField = dividendRate + + /** + * Returns the raw JSON value of [nav]. + * + * Unlike [nav], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("nav") @ExcludeMissing fun _nav(): JsonField = nav + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [units]. + * + * Unlike [units], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Transaction]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Transaction]. */ + class Builder internal constructor() { + + private var additionalInfo: JsonField = JsonMissing.of() + private var amount: JsonField = JsonMissing.of() + private var balance: JsonField = JsonMissing.of() + private var date: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var dividendRate: JsonField = JsonMissing.of() + private var nav: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var units: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(transaction: Transaction) = apply { + additionalInfo = transaction.additionalInfo + amount = transaction.amount + balance = transaction.balance + date = transaction.date + description = transaction.description + dividendRate = transaction.dividendRate + nav = transaction.nav + type = transaction.type + units = transaction.units + additionalProperties = transaction.additionalProperties.toMutableMap() + } + + /** Additional transaction-specific fields that vary by source */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) + + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { + this.additionalInfo = additionalInfo + } + + /** Transaction amount in currency (computed from units × price/NAV) */ + fun amount(amount: Float?) = amount(JsonField.ofNullable(amount)) + + /** + * Alias for [Builder.amount]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun amount(amount: Float) = amount(amount as Float?) + + /** Alias for calling [Builder.amount] with `amount.orElse(null)`. */ + fun amount(amount: Optional) = amount(amount.getOrNull()) + + /** + * Sets [Builder.amount] to an arbitrary JSON value. + * + * You should usually call [Builder.amount] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun amount(amount: JsonField) = apply { this.amount = amount } + + /** Balance units after transaction */ + fun balance(balance: Float) = balance(JsonField.of(balance)) + + /** + * Sets [Builder.balance] to an arbitrary JSON value. + * + * You should usually call [Builder.balance] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun balance(balance: JsonField) = apply { this.balance = balance } + + /** Transaction date (YYYY-MM-DD) */ + fun date(date: LocalDate) = date(JsonField.of(date)) + + /** + * Sets [Builder.date] to an arbitrary JSON value. + * + * You should usually call [Builder.date] with a well-typed [LocalDate] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun date(date: JsonField) = apply { this.date = date } + + /** Transaction description/particulars */ + fun description(description: String) = + description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } + + /** Dividend rate (for DIVIDEND_PAYOUT transactions) */ + fun dividendRate(dividendRate: Float?) = + dividendRate(JsonField.ofNullable(dividendRate)) + + /** + * Alias for [Builder.dividendRate]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun dividendRate(dividendRate: Float) = dividendRate(dividendRate as Float?) + + /** + * Alias for calling [Builder.dividendRate] with + * `dividendRate.orElse(null)`. + */ + fun dividendRate(dividendRate: Optional) = + dividendRate(dividendRate.getOrNull()) + + /** + * Sets [Builder.dividendRate] to an arbitrary JSON value. + * + * You should usually call [Builder.dividendRate] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun dividendRate(dividendRate: JsonField) = apply { + this.dividendRate = dividendRate + } + + /** NAV/price per unit on transaction date */ + fun nav(nav: Float?) = nav(JsonField.ofNullable(nav)) + + /** + * Alias for [Builder.nav]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun nav(nav: Float) = nav(nav as Float?) + + /** Alias for calling [Builder.nav] with `nav.orElse(null)`. */ + fun nav(nav: Optional) = nav(nav.getOrNull()) + + /** + * Sets [Builder.nav] to an arbitrary JSON value. + * + * You should usually call [Builder.nav] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun nav(nav: JsonField) = apply { this.nav = nav } + + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, + * DIVIDEND_PAYOUT, DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, + * STT_TAX, MISC, REVERSAL, UNKNOWN. + */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + /** Number of units involved in transaction */ + fun units(units: Float) = units(JsonField.of(units)) + + /** + * Sets [Builder.units] to an arbitrary JSON value. + * + * You should usually call [Builder.units] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun units(units: JsonField) = apply { this.units = units } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Transaction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Transaction = + Transaction( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Transaction = apply { + if (validated) { + return@apply + } + + additionalInfo().ifPresent { it.validate() } + amount() + balance() + date() + description() + dividendRate() + nav() + type().ifPresent { it.validate() } + units() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (amount.asKnown().isPresent) 1 else 0) + + (if (balance.asKnown().isPresent) 1 else 0) + + (if (date.asKnown().isPresent) 1 else 0) + + (if (description.asKnown().isPresent) 1 else 0) + + (if (dividendRate.asKnown().isPresent) 1 else 0) + + (if (nav.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (units.asKnown().isPresent) 1 else 0) + + /** Additional transaction-specific fields that vary by source */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val capitalWithdrawal: JsonField, + private val credit: JsonField, + private val debit: JsonField, + private val incomeDistribution: JsonField, + private val orderNo: JsonField, + private val price: JsonField, + private val stampDuty: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("capital_withdrawal") + @ExcludeMissing + capitalWithdrawal: JsonField = JsonMissing.of(), + @JsonProperty("credit") + @ExcludeMissing + credit: JsonField = JsonMissing.of(), + @JsonProperty("debit") + @ExcludeMissing + debit: JsonField = JsonMissing.of(), + @JsonProperty("income_distribution") + @ExcludeMissing + incomeDistribution: JsonField = JsonMissing.of(), + @JsonProperty("order_no") + @ExcludeMissing + orderNo: JsonField = JsonMissing.of(), + @JsonProperty("price") + @ExcludeMissing + price: JsonField = JsonMissing.of(), + @JsonProperty("stamp_duty") + @ExcludeMissing + stampDuty: JsonField = JsonMissing.of(), + ) : this( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + mutableMapOf(), + ) + + /** + * Capital withdrawal amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun capitalWithdrawal(): Optional = + capitalWithdrawal.getOptional("capital_withdrawal") + + /** + * Units credited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun credit(): Optional = credit.getOptional("credit") + + /** + * Units debited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun debit(): Optional = debit.getOptional("debit") + + /** + * Income distribution amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun incomeDistribution(): Optional = + incomeDistribution.getOptional("income_distribution") + + /** + * Order/transaction reference number (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun orderNo(): Optional = orderNo.getOptional("order_no") + + /** + * Price per unit (NSDL/CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun price(): Optional = price.getOptional("price") + + /** + * Stamp duty charged + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun stampDuty(): Optional = stampDuty.getOptional("stamp_duty") + + /** + * Returns the raw JSON value of [capitalWithdrawal]. + * + * Unlike [capitalWithdrawal], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("capital_withdrawal") + @ExcludeMissing + fun _capitalWithdrawal(): JsonField = capitalWithdrawal + + /** + * Returns the raw JSON value of [credit]. + * + * Unlike [credit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("credit") + @ExcludeMissing + fun _credit(): JsonField = credit + + /** + * Returns the raw JSON value of [debit]. + * + * Unlike [debit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("debit") + @ExcludeMissing + fun _debit(): JsonField = debit + + /** + * Returns the raw JSON value of [incomeDistribution]. + * + * Unlike [incomeDistribution], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("income_distribution") + @ExcludeMissing + fun _incomeDistribution(): JsonField = incomeDistribution + + /** + * Returns the raw JSON value of [orderNo]. + * + * Unlike [orderNo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("order_no") + @ExcludeMissing + fun _orderNo(): JsonField = orderNo + + /** + * Returns the raw JSON value of [price]. + * + * Unlike [price], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("price") + @ExcludeMissing + fun _price(): JsonField = price + + /** + * Returns the raw JSON value of [stampDuty]. + * + * Unlike [stampDuty], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("stamp_duty") + @ExcludeMissing + fun _stampDuty(): JsonField = stampDuty + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { + + private var capitalWithdrawal: JsonField = JsonMissing.of() + private var credit: JsonField = JsonMissing.of() + private var debit: JsonField = JsonMissing.of() + private var incomeDistribution: JsonField = JsonMissing.of() + private var orderNo: JsonField = JsonMissing.of() + private var price: JsonField = JsonMissing.of() + private var stampDuty: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + capitalWithdrawal = additionalInfo.capitalWithdrawal + credit = additionalInfo.credit + debit = additionalInfo.debit + incomeDistribution = additionalInfo.incomeDistribution + orderNo = additionalInfo.orderNo + price = additionalInfo.price + stampDuty = additionalInfo.stampDuty + additionalProperties = + additionalInfo.additionalProperties.toMutableMap() + } + + /** Capital withdrawal amount (CDSL MF transactions) */ + fun capitalWithdrawal(capitalWithdrawal: Float) = + capitalWithdrawal(JsonField.of(capitalWithdrawal)) + + /** + * Sets [Builder.capitalWithdrawal] to an arbitrary JSON value. + * + * You should usually call [Builder.capitalWithdrawal] with a well-typed + * [Float] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun capitalWithdrawal(capitalWithdrawal: JsonField) = apply { + this.capitalWithdrawal = capitalWithdrawal + } + + /** Units credited (demat transactions) */ + fun credit(credit: Float) = credit(JsonField.of(credit)) + + /** + * Sets [Builder.credit] to an arbitrary JSON value. + * + * You should usually call [Builder.credit] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun credit(credit: JsonField) = apply { this.credit = credit } + + /** Units debited (demat transactions) */ + fun debit(debit: Float) = debit(JsonField.of(debit)) + + /** + * Sets [Builder.debit] to an arbitrary JSON value. + * + * You should usually call [Builder.debit] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun debit(debit: JsonField) = apply { this.debit = debit } + + /** Income distribution amount (CDSL MF transactions) */ + fun incomeDistribution(incomeDistribution: Float) = + incomeDistribution(JsonField.of(incomeDistribution)) + + /** + * Sets [Builder.incomeDistribution] to an arbitrary JSON value. + * + * You should usually call [Builder.incomeDistribution] with a + * well-typed [Float] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun incomeDistribution(incomeDistribution: JsonField) = apply { + this.incomeDistribution = incomeDistribution + } + + /** Order/transaction reference number (demat transactions) */ + fun orderNo(orderNo: String) = orderNo(JsonField.of(orderNo)) + + /** + * Sets [Builder.orderNo] to an arbitrary JSON value. + * + * You should usually call [Builder.orderNo] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun orderNo(orderNo: JsonField) = apply { + this.orderNo = orderNo + } + + /** Price per unit (NSDL/CDSL MF transactions) */ + fun price(price: Float) = price(JsonField.of(price)) + + /** + * Sets [Builder.price] to an arbitrary JSON value. + * + * You should usually call [Builder.price] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun price(price: JsonField) = apply { this.price = price } + + /** Stamp duty charged */ + fun stampDuty(stampDuty: Float) = stampDuty(JsonField.of(stampDuty)) + + /** + * Sets [Builder.stampDuty] to an arbitrary JSON value. + * + * You should usually call [Builder.stampDuty] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun stampDuty(stampDuty: JsonField) = apply { + this.stampDuty = stampDuty + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } + + capitalWithdrawal() + credit() + debit() + incomeDistribution() + orderNo() + price() + stampDuty() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (capitalWithdrawal.asKnown().isPresent) 1 else 0) + + (if (credit.asKnown().isPresent) 1 else 0) + + (if (debit.asKnown().isPresent) 1 else 0) + + (if (incomeDistribution.asKnown().isPresent) 1 else 0) + + (if (orderNo.asKnown().isPresent) 1 else 0) + + (if (price.asKnown().isPresent) 1 else 0) + + (if (stampDuty.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AdditionalInfo && + capitalWithdrawal == other.capitalWithdrawal && + credit == other.credit && + debit == other.debit && + incomeDistribution == other.incomeDistribution && + orderNo == other.orderNo && + price == other.price && + stampDuty == other.stampDuty && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AdditionalInfo{capitalWithdrawal=$capitalWithdrawal, credit=$credit, debit=$debit, incomeDistribution=$incomeDistribution, orderNo=$orderNo, price=$price, stampDuty=$stampDuty, additionalProperties=$additionalProperties}" + } + + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, + * REVERSAL, UNKNOWN. + */ + class Type + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data + * that doesn't match any known 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. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value + + companion object { + + @JvmField val PURCHASE = of("PURCHASE") + + @JvmField val PURCHASE_SIP = of("PURCHASE_SIP") + + @JvmField val REDEMPTION = of("REDEMPTION") + + @JvmField val SWITCH_IN = of("SWITCH_IN") + + @JvmField val SWITCH_IN_MERGER = of("SWITCH_IN_MERGER") + + @JvmField val SWITCH_OUT = of("SWITCH_OUT") + + @JvmField val SWITCH_OUT_MERGER = of("SWITCH_OUT_MERGER") + + @JvmField val DIVIDEND_PAYOUT = of("DIVIDEND_PAYOUT") + + @JvmField val DIVIDEND_REINVEST = of("DIVIDEND_REINVEST") + + @JvmField val SEGREGATION = of("SEGREGATION") + + @JvmField val STAMP_DUTY_TAX = of("STAMP_DUTY_TAX") + + @JvmField val TDS_TAX = of("TDS_TAX") + + @JvmField val STT_TAX = of("STT_TAX") + + @JvmField val MISC = of("MISC") + + @JvmField val REVERSAL = of("REVERSAL") + + @JvmField val UNKNOWN = of("UNKNOWN") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. 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. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + /** + * An enum member indicating that [Type] was instantiated with an + * unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always + * known or if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + PURCHASE -> Value.PURCHASE + PURCHASE_SIP -> Value.PURCHASE_SIP + REDEMPTION -> Value.REDEMPTION + SWITCH_IN -> Value.SWITCH_IN + SWITCH_IN_MERGER -> Value.SWITCH_IN_MERGER + SWITCH_OUT -> Value.SWITCH_OUT + SWITCH_OUT_MERGER -> Value.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Value.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Value.DIVIDEND_REINVEST + SEGREGATION -> Value.SEGREGATION + STAMP_DUTY_TAX -> Value.STAMP_DUTY_TAX + TDS_TAX -> Value.TDS_TAX + STT_TAX -> Value.STT_TAX + MISC -> Value.MISC + REVERSAL -> Value.REVERSAL + UNKNOWN -> Value.UNKNOWN + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always + * known and don't want to throw for the unknown case. + * + * @throws CasParserInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + PURCHASE -> Known.PURCHASE + PURCHASE_SIP -> Known.PURCHASE_SIP + REDEMPTION -> Known.REDEMPTION + SWITCH_IN -> Known.SWITCH_IN + SWITCH_IN_MERGER -> Known.SWITCH_IN_MERGER + SWITCH_OUT -> Known.SWITCH_OUT + SWITCH_OUT_MERGER -> Known.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Known.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Known.DIVIDEND_REINVEST + SEGREGATION -> Known.SEGREGATION + STAMP_DUTY_TAX -> Known.STAMP_DUTY_TAX + TDS_TAX -> Known.TDS_TAX + STT_TAX -> Known.STT_TAX + MISC -> Known.MISC + REVERSAL -> Known.REVERSAL + UNKNOWN -> Known.UNKNOWN + else -> throw CasParserInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily + * for debugging and generally doesn't throw. + * + * @throws CasParserInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + CasParserInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Transaction && + additionalInfo == other.additionalInfo && + amount == other.amount && + balance == other.balance && + date == other.date && + description == other.description && + dividendRate == other.dividendRate && + nav == other.nav && + type == other.type && + units == other.units && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Transaction{additionalInfo=$additionalInfo, amount=$amount, balance=$balance, date=$date, description=$description, dividendRate=$dividendRate, nav=$nav, type=$type, units=$units, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GovernmentSecurity && + additionalInfo == other.additionalInfo && + isin == other.isin && + name == other.name && + transactions == other.transactions && + units == other.units && + value == other.value && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + isin, + name, + transactions, + units, + value, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GovernmentSecurity{additionalInfo=$additionalInfo, isin=$isin, name=$name, transactions=$transactions, units=$units, value=$value, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Holdings && + aifs == other.aifs && + corporateBonds == other.corporateBonds && + dematMutualFunds == other.dematMutualFunds && + equities == other.equities && + governmentSecurities == other.governmentSecurities && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + aifs, + corporateBonds, + dematMutualFunds, + equities, + governmentSecurities, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Holdings{aifs=$aifs, corporateBonds=$corporateBonds, dematMutualFunds=$dematMutualFunds, equities=$equities, governmentSecurities=$governmentSecurities, additionalProperties=$additionalProperties}" + } + + class LinkedHolder + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val pan: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("pan") @ExcludeMissing pan: JsonField = JsonMissing.of(), + ) : this(name, pan, mutableMapOf()) + + /** + * Name of the account holder + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * PAN of the account holder + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun pan(): Optional = pan.getOptional("pan") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [pan]. + * + * Unlike [pan], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pan") @ExcludeMissing fun _pan(): JsonField = pan + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [LinkedHolder]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [LinkedHolder]. */ + class Builder internal constructor() { + + private var name: JsonField = JsonMissing.of() + private var pan: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(linkedHolder: LinkedHolder) = apply { + name = linkedHolder.name + pan = linkedHolder.pan + additionalProperties = linkedHolder.additionalProperties.toMutableMap() + } + + /** Name of the account holder */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** PAN of the account holder */ + fun pan(pan: String) = pan(JsonField.of(pan)) + + /** + * Sets [Builder.pan] to an arbitrary JSON value. + * + * You should usually call [Builder.pan] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun pan(pan: JsonField) = apply { this.pan = pan } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [LinkedHolder]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): LinkedHolder = + LinkedHolder(name, pan, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): LinkedHolder = apply { + if (validated) { + return@apply + } + + name() + pan() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (name.asKnown().isPresent) 1 else 0) + (if (pan.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is LinkedHolder && + name == other.name && + pan == other.pan && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(name, pan, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "LinkedHolder{name=$name, pan=$pan, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is DematAccount && + additionalInfo == other.additionalInfo && + boId == other.boId && + clientId == other.clientId && + dematType == other.dematType && + dpId == other.dpId && + dpName == other.dpName && + holdings == other.holdings && + linkedHolders == other.linkedHolders && + value == other.value && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + boId, + clientId, + dematType, + dpId, + dpName, + holdings, + linkedHolders, + value, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "DematAccount{additionalInfo=$additionalInfo, boId=$boId, clientId=$clientId, dematType=$dematType, dpId=$dpId, dpName=$dpName, holdings=$holdings, linkedHolders=$linkedHolders, value=$value, additionalProperties=$additionalProperties}" + } + + class Insurance + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val lifeInsurancePolicies: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("life_insurance_policies") + @ExcludeMissing + lifeInsurancePolicies: JsonField> = JsonMissing.of() + ) : this(lifeInsurancePolicies, mutableMapOf()) + + /** + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun lifeInsurancePolicies(): Optional> = + lifeInsurancePolicies.getOptional("life_insurance_policies") + + /** + * Returns the raw JSON value of [lifeInsurancePolicies]. + * + * Unlike [lifeInsurancePolicies], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("life_insurance_policies") + @ExcludeMissing + fun _lifeInsurancePolicies(): JsonField> = lifeInsurancePolicies + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Insurance]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Insurance]. */ + class Builder internal constructor() { + + private var lifeInsurancePolicies: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(insurance: Insurance) = apply { + lifeInsurancePolicies = insurance.lifeInsurancePolicies.map { it.toMutableList() } + additionalProperties = insurance.additionalProperties.toMutableMap() + } + + fun lifeInsurancePolicies(lifeInsurancePolicies: List) = + lifeInsurancePolicies(JsonField.of(lifeInsurancePolicies)) + + /** + * Sets [Builder.lifeInsurancePolicies] to an arbitrary JSON value. + * + * You should usually call [Builder.lifeInsurancePolicies] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun lifeInsurancePolicies(lifeInsurancePolicies: JsonField>) = + apply { + this.lifeInsurancePolicies = lifeInsurancePolicies.map { it.toMutableList() } + } + + /** + * Adds a single [LifeInsurancePolicy] to [lifeInsurancePolicies]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addLifeInsurancePolicy(lifeInsurancePolicy: LifeInsurancePolicy) = apply { + lifeInsurancePolicies = + (lifeInsurancePolicies ?: JsonField.of(mutableListOf())).also { + checkKnown("lifeInsurancePolicies", it).add(lifeInsurancePolicy) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Insurance]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Insurance = + Insurance( + (lifeInsurancePolicies ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Insurance = apply { + if (validated) { + return@apply + } + + lifeInsurancePolicies().ifPresent { it.forEach { it.validate() } } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (lifeInsurancePolicies.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + class LifeInsurancePolicy + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonValue, + private val lifeAssured: JsonField, + private val policyName: JsonField, + private val policyNumber: JsonField, + private val premiumAmount: JsonField, + private val premiumFrequency: JsonField, + private val provider: JsonField, + private val status: JsonField, + private val sumAssured: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonValue = JsonMissing.of(), + @JsonProperty("life_assured") + @ExcludeMissing + lifeAssured: JsonField = JsonMissing.of(), + @JsonProperty("policy_name") + @ExcludeMissing + policyName: JsonField = JsonMissing.of(), + @JsonProperty("policy_number") + @ExcludeMissing + policyNumber: JsonField = JsonMissing.of(), + @JsonProperty("premium_amount") + @ExcludeMissing + premiumAmount: JsonField = JsonMissing.of(), + @JsonProperty("premium_frequency") + @ExcludeMissing + premiumFrequency: JsonField = JsonMissing.of(), + @JsonProperty("provider") + @ExcludeMissing + provider: JsonField = JsonMissing.of(), + @JsonProperty("status") + @ExcludeMissing + status: JsonField = JsonMissing.of(), + @JsonProperty("sum_assured") + @ExcludeMissing + sumAssured: JsonField = JsonMissing.of(), + ) : this( + additionalInfo, + lifeAssured, + policyName, + policyNumber, + premiumAmount, + premiumFrequency, + provider, + status, + sumAssured, + mutableMapOf(), + ) + + /** Additional information specific to the policy */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonValue = additionalInfo + + /** + * Name of the life assured + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun lifeAssured(): Optional = lifeAssured.getOptional("life_assured") + + /** + * Name of the insurance policy + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun policyName(): Optional = policyName.getOptional("policy_name") + + /** + * Insurance policy number + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun policyNumber(): Optional = policyNumber.getOptional("policy_number") + + /** + * Premium amount + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun premiumAmount(): Optional = premiumAmount.getOptional("premium_amount") + + /** + * Frequency of premium payment (e.g., Annual, Monthly) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun premiumFrequency(): Optional = + premiumFrequency.getOptional("premium_frequency") + + /** + * Insurance company name + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun provider(): Optional = provider.getOptional("provider") + + /** + * Status of the policy (e.g., Active, Lapsed) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun status(): Optional = status.getOptional("status") + + /** + * Sum assured amount + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun sumAssured(): Optional = sumAssured.getOptional("sum_assured") + + /** + * Returns the raw JSON value of [lifeAssured]. + * + * Unlike [lifeAssured], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("life_assured") + @ExcludeMissing + fun _lifeAssured(): JsonField = lifeAssured + + /** + * Returns the raw JSON value of [policyName]. + * + * Unlike [policyName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("policy_name") + @ExcludeMissing + fun _policyName(): JsonField = policyName + + /** + * Returns the raw JSON value of [policyNumber]. + * + * Unlike [policyNumber], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("policy_number") + @ExcludeMissing + fun _policyNumber(): JsonField = policyNumber + + /** + * Returns the raw JSON value of [premiumAmount]. + * + * Unlike [premiumAmount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("premium_amount") + @ExcludeMissing + fun _premiumAmount(): JsonField = premiumAmount + + /** + * Returns the raw JSON value of [premiumFrequency]. + * + * Unlike [premiumFrequency], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("premium_frequency") + @ExcludeMissing + fun _premiumFrequency(): JsonField = premiumFrequency + + /** + * Returns the raw JSON value of [provider]. + * + * Unlike [provider], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider + + /** + * Returns the raw JSON value of [status]. + * + * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + + /** + * Returns the raw JSON value of [sumAssured]. + * + * Unlike [sumAssured], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("sum_assured") + @ExcludeMissing + fun _sumAssured(): JsonField = sumAssured + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [LifeInsurancePolicy]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [LifeInsurancePolicy]. */ + class Builder internal constructor() { + + private var additionalInfo: JsonValue = JsonMissing.of() + private var lifeAssured: JsonField = JsonMissing.of() + private var policyName: JsonField = JsonMissing.of() + private var policyNumber: JsonField = JsonMissing.of() + private var premiumAmount: JsonField = JsonMissing.of() + private var premiumFrequency: JsonField = JsonMissing.of() + private var provider: JsonField = JsonMissing.of() + private var status: JsonField = JsonMissing.of() + private var sumAssured: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(lifeInsurancePolicy: LifeInsurancePolicy) = apply { + additionalInfo = lifeInsurancePolicy.additionalInfo + lifeAssured = lifeInsurancePolicy.lifeAssured + policyName = lifeInsurancePolicy.policyName + policyNumber = lifeInsurancePolicy.policyNumber + premiumAmount = lifeInsurancePolicy.premiumAmount + premiumFrequency = lifeInsurancePolicy.premiumFrequency + provider = lifeInsurancePolicy.provider + status = lifeInsurancePolicy.status + sumAssured = lifeInsurancePolicy.sumAssured + additionalProperties = lifeInsurancePolicy.additionalProperties.toMutableMap() + } + + /** Additional information specific to the policy */ + fun additionalInfo(additionalInfo: JsonValue) = apply { + this.additionalInfo = additionalInfo + } + + /** Name of the life assured */ + fun lifeAssured(lifeAssured: String) = lifeAssured(JsonField.of(lifeAssured)) + + /** + * Sets [Builder.lifeAssured] to an arbitrary JSON value. + * + * You should usually call [Builder.lifeAssured] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun lifeAssured(lifeAssured: JsonField) = apply { + this.lifeAssured = lifeAssured + } + + /** Name of the insurance policy */ + fun policyName(policyName: String) = policyName(JsonField.of(policyName)) + + /** + * Sets [Builder.policyName] to an arbitrary JSON value. + * + * You should usually call [Builder.policyName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun policyName(policyName: JsonField) = apply { + this.policyName = policyName + } + + /** Insurance policy number */ + fun policyNumber(policyNumber: String) = policyNumber(JsonField.of(policyNumber)) + + /** + * Sets [Builder.policyNumber] to an arbitrary JSON value. + * + * You should usually call [Builder.policyNumber] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun policyNumber(policyNumber: JsonField) = apply { + this.policyNumber = policyNumber + } + + /** Premium amount */ + fun premiumAmount(premiumAmount: Float) = premiumAmount(JsonField.of(premiumAmount)) + + /** + * Sets [Builder.premiumAmount] to an arbitrary JSON value. + * + * You should usually call [Builder.premiumAmount] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun premiumAmount(premiumAmount: JsonField) = apply { + this.premiumAmount = premiumAmount + } + + /** Frequency of premium payment (e.g., Annual, Monthly) */ + fun premiumFrequency(premiumFrequency: String) = + premiumFrequency(JsonField.of(premiumFrequency)) + + /** + * Sets [Builder.premiumFrequency] to an arbitrary JSON value. + * + * You should usually call [Builder.premiumFrequency] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun premiumFrequency(premiumFrequency: JsonField) = apply { + this.premiumFrequency = premiumFrequency + } + + /** Insurance company name */ + fun provider(provider: String) = provider(JsonField.of(provider)) + + /** + * Sets [Builder.provider] to an arbitrary JSON value. + * + * You should usually call [Builder.provider] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun provider(provider: JsonField) = apply { this.provider = provider } + + /** Status of the policy (e.g., Active, Lapsed) */ + fun status(status: String) = status(JsonField.of(status)) + + /** + * Sets [Builder.status] to an arbitrary JSON value. + * + * You should usually call [Builder.status] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun status(status: JsonField) = apply { this.status = status } + + /** Sum assured amount */ + fun sumAssured(sumAssured: Float) = sumAssured(JsonField.of(sumAssured)) + + /** + * Sets [Builder.sumAssured] to an arbitrary JSON value. + * + * You should usually call [Builder.sumAssured] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun sumAssured(sumAssured: JsonField) = apply { + this.sumAssured = sumAssured + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [LifeInsurancePolicy]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): LifeInsurancePolicy = + LifeInsurancePolicy( + additionalInfo, + lifeAssured, + policyName, + policyNumber, + premiumAmount, + premiumFrequency, + provider, + status, + sumAssured, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): LifeInsurancePolicy = apply { + if (validated) { + return@apply + } + + lifeAssured() + policyName() + policyNumber() + premiumAmount() + premiumFrequency() + provider() + status() + sumAssured() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (lifeAssured.asKnown().isPresent) 1 else 0) + + (if (policyName.asKnown().isPresent) 1 else 0) + + (if (policyNumber.asKnown().isPresent) 1 else 0) + + (if (premiumAmount.asKnown().isPresent) 1 else 0) + + (if (premiumFrequency.asKnown().isPresent) 1 else 0) + + (if (provider.asKnown().isPresent) 1 else 0) + + (if (status.asKnown().isPresent) 1 else 0) + + (if (sumAssured.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is LifeInsurancePolicy && + additionalInfo == other.additionalInfo && + lifeAssured == other.lifeAssured && + policyName == other.policyName && + policyNumber == other.policyNumber && + premiumAmount == other.premiumAmount && + premiumFrequency == other.premiumFrequency && + provider == other.provider && + status == other.status && + sumAssured == other.sumAssured && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + lifeAssured, + policyName, + policyNumber, + premiumAmount, + premiumFrequency, + provider, + status, + sumAssured, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "LifeInsurancePolicy{additionalInfo=$additionalInfo, lifeAssured=$lifeAssured, policyName=$policyName, policyNumber=$policyNumber, premiumAmount=$premiumAmount, premiumFrequency=$premiumFrequency, provider=$provider, status=$status, sumAssured=$sumAssured, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Insurance && + lifeInsurancePolicies == other.lifeInsurancePolicies && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(lifeInsurancePolicies, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Insurance{lifeInsurancePolicies=$lifeInsurancePolicies, additionalProperties=$additionalProperties}" + } + + class Investor + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val address: JsonField, + private val casId: JsonField, + private val email: JsonField, + private val mobile: JsonField, + private val name: JsonField, + private val pan: JsonField, + private val pincode: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("address") @ExcludeMissing address: JsonField = JsonMissing.of(), + @JsonProperty("cas_id") @ExcludeMissing casId: JsonField = JsonMissing.of(), + @JsonProperty("email") @ExcludeMissing email: JsonField = JsonMissing.of(), + @JsonProperty("mobile") @ExcludeMissing mobile: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("pan") @ExcludeMissing pan: JsonField = JsonMissing.of(), + @JsonProperty("pincode") @ExcludeMissing pincode: JsonField = JsonMissing.of(), + ) : this(address, casId, email, mobile, name, pan, pincode, mutableMapOf()) + + /** + * Address of the investor + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun address(): Optional = address.getOptional("address") + + /** + * CAS ID of the investor (only for NSDL and CDSL) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun casId(): Optional = casId.getOptional("cas_id") + + /** + * Email address of the investor + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun email(): Optional = email.getOptional("email") + + /** + * Mobile number of the investor + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun mobile(): Optional = mobile.getOptional("mobile") + + /** + * Name of the investor + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * PAN (Permanent Account Number) of the investor + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun pan(): Optional = pan.getOptional("pan") + + /** + * Postal code of the investor's address + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun pincode(): Optional = pincode.getOptional("pincode") + + /** + * Returns the raw JSON value of [address]. + * + * Unlike [address], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("address") @ExcludeMissing fun _address(): JsonField = address + + /** + * Returns the raw JSON value of [casId]. + * + * Unlike [casId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cas_id") @ExcludeMissing fun _casId(): JsonField = casId + + /** + * Returns the raw JSON value of [email]. + * + * Unlike [email], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("email") @ExcludeMissing fun _email(): JsonField = email + + /** + * Returns the raw JSON value of [mobile]. + * + * Unlike [mobile], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("mobile") @ExcludeMissing fun _mobile(): JsonField = mobile + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [pan]. + * + * Unlike [pan], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pan") @ExcludeMissing fun _pan(): JsonField = pan + + /** + * Returns the raw JSON value of [pincode]. + * + * Unlike [pincode], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pincode") @ExcludeMissing fun _pincode(): JsonField = pincode + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Investor]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Investor]. */ + class Builder internal constructor() { + + private var address: JsonField = JsonMissing.of() + private var casId: JsonField = JsonMissing.of() + private var email: JsonField = JsonMissing.of() + private var mobile: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var pan: JsonField = JsonMissing.of() + private var pincode: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(investor: Investor) = apply { + address = investor.address + casId = investor.casId + email = investor.email + mobile = investor.mobile + name = investor.name + pan = investor.pan + pincode = investor.pincode + additionalProperties = investor.additionalProperties.toMutableMap() + } + + /** Address of the investor */ + fun address(address: String) = address(JsonField.of(address)) + + /** + * Sets [Builder.address] to an arbitrary JSON value. + * + * You should usually call [Builder.address] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun address(address: JsonField) = apply { this.address = address } + + /** CAS ID of the investor (only for NSDL and CDSL) */ + fun casId(casId: String) = casId(JsonField.of(casId)) + + /** + * Sets [Builder.casId] to an arbitrary JSON value. + * + * You should usually call [Builder.casId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun casId(casId: JsonField) = apply { this.casId = casId } + + /** Email address of the investor */ + fun email(email: String) = email(JsonField.of(email)) + + /** + * Sets [Builder.email] to an arbitrary JSON value. + * + * You should usually call [Builder.email] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun email(email: JsonField) = apply { this.email = email } + + /** Mobile number of the investor */ + fun mobile(mobile: String) = mobile(JsonField.of(mobile)) + + /** + * Sets [Builder.mobile] to an arbitrary JSON value. + * + * You should usually call [Builder.mobile] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun mobile(mobile: JsonField) = apply { this.mobile = mobile } + + /** Name of the investor */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** PAN (Permanent Account Number) of the investor */ + fun pan(pan: String) = pan(JsonField.of(pan)) + + /** + * Sets [Builder.pan] to an arbitrary JSON value. + * + * You should usually call [Builder.pan] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun pan(pan: JsonField) = apply { this.pan = pan } + + /** Postal code of the investor's address */ + fun pincode(pincode: String) = pincode(JsonField.of(pincode)) + + /** + * Sets [Builder.pincode] to an arbitrary JSON value. + * + * You should usually call [Builder.pincode] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun pincode(pincode: JsonField) = apply { this.pincode = pincode } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Investor]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Investor = + Investor( + address, + casId, + email, + mobile, + name, + pan, + pincode, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Investor = apply { + if (validated) { + return@apply + } + + address() + casId() + email() + mobile() + name() + pan() + pincode() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (address.asKnown().isPresent) 1 else 0) + + (if (casId.asKnown().isPresent) 1 else 0) + + (if (email.asKnown().isPresent) 1 else 0) + + (if (mobile.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (pan.asKnown().isPresent) 1 else 0) + + (if (pincode.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Investor && + address == other.address && + casId == other.casId && + email == other.email && + mobile == other.mobile && + name == other.name && + pan == other.pan && + pincode == other.pincode && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(address, casId, email, mobile, name, pan, pincode, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Investor{address=$address, casId=$casId, email=$email, mobile=$mobile, name=$name, pan=$pan, pincode=$pincode, additionalProperties=$additionalProperties}" + } + + class Meta + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val casType: JsonField, + private val generatedAt: JsonField, + private val statementPeriod: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("cas_type") + @ExcludeMissing + casType: JsonField = JsonMissing.of(), + @JsonProperty("generated_at") + @ExcludeMissing + generatedAt: JsonField = JsonMissing.of(), + @JsonProperty("statement_period") + @ExcludeMissing + statementPeriod: JsonField = JsonMissing.of(), + ) : this(casType, generatedAt, statementPeriod, mutableMapOf()) + + /** + * Type of CAS detected and processed + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun casType(): Optional = casType.getOptional("cas_type") + + /** + * Timestamp when the response was generated + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun generatedAt(): Optional = generatedAt.getOptional("generated_at") + + /** + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun statementPeriod(): Optional = + statementPeriod.getOptional("statement_period") + + /** + * Returns the raw JSON value of [casType]. + * + * Unlike [casType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cas_type") @ExcludeMissing fun _casType(): JsonField = casType + + /** + * Returns the raw JSON value of [generatedAt]. + * + * Unlike [generatedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("generated_at") + @ExcludeMissing + fun _generatedAt(): JsonField = generatedAt + + /** + * Returns the raw JSON value of [statementPeriod]. + * + * Unlike [statementPeriod], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("statement_period") + @ExcludeMissing + fun _statementPeriod(): JsonField = statementPeriod + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Meta]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Meta]. */ + class Builder internal constructor() { + + private var casType: JsonField = JsonMissing.of() + private var generatedAt: JsonField = JsonMissing.of() + private var statementPeriod: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(meta: Meta) = apply { + casType = meta.casType + generatedAt = meta.generatedAt + statementPeriod = meta.statementPeriod + additionalProperties = meta.additionalProperties.toMutableMap() + } + + /** Type of CAS detected and processed */ + fun casType(casType: CasType) = casType(JsonField.of(casType)) + + /** + * Sets [Builder.casType] to an arbitrary JSON value. + * + * You should usually call [Builder.casType] with a well-typed [CasType] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun casType(casType: JsonField) = apply { this.casType = casType } + + /** Timestamp when the response was generated */ + fun generatedAt(generatedAt: OffsetDateTime) = generatedAt(JsonField.of(generatedAt)) + + /** + * Sets [Builder.generatedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.generatedAt] with a well-typed [OffsetDateTime] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun generatedAt(generatedAt: JsonField) = apply { + this.generatedAt = generatedAt + } + + fun statementPeriod(statementPeriod: StatementPeriod) = + statementPeriod(JsonField.of(statementPeriod)) + + /** + * Sets [Builder.statementPeriod] to an arbitrary JSON value. + * + * You should usually call [Builder.statementPeriod] with a well-typed [StatementPeriod] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun statementPeriod(statementPeriod: JsonField) = apply { + this.statementPeriod = statementPeriod + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Meta]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Meta = + Meta(casType, generatedAt, statementPeriod, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Meta = apply { + if (validated) { + return@apply + } + + casType().ifPresent { it.validate() } + generatedAt() + statementPeriod().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (casType.asKnown().getOrNull()?.validity() ?: 0) + + (if (generatedAt.asKnown().isPresent) 1 else 0) + + (statementPeriod.asKnown().getOrNull()?.validity() ?: 0) + + /** Type of CAS detected and processed */ + class CasType @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known 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. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val NSDL = of("NSDL") + + @JvmField val CDSL = of("CDSL") + + @JvmField val CAMS_KFINTECH = of("CAMS_KFINTECH") + + @JvmStatic fun of(value: String) = CasType(JsonField.of(value)) + } + + /** An enum containing [CasType]'s known values. */ + enum class Known { + NSDL, + CDSL, + CAMS_KFINTECH, + } + + /** + * An enum containing [CasType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [CasType] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. 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. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + NSDL, + CDSL, + CAMS_KFINTECH, + /** + * An enum member indicating that [CasType] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + NSDL -> Value.NSDL + CDSL -> Value.CDSL + CAMS_KFINTECH -> Value.CAMS_KFINTECH + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws CasParserInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + NSDL -> Known.NSDL + CDSL -> Known.CDSL + CAMS_KFINTECH -> Known.CAMS_KFINTECH + else -> throw CasParserInvalidDataException("Unknown CasType: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws CasParserInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + CasParserInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): CasType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is CasType && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class StatementPeriod + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val from: JsonField, + private val to: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("from") @ExcludeMissing from: JsonField = JsonMissing.of(), + @JsonProperty("to") @ExcludeMissing to: JsonField = JsonMissing.of(), + ) : this(from, to, mutableMapOf()) + + /** + * Start date of the statement period + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun from(): Optional = from.getOptional("from") + + /** + * End date of the statement period + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun to(): Optional = to.getOptional("to") + + /** + * Returns the raw JSON value of [from]. + * + * Unlike [from], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("from") @ExcludeMissing fun _from(): JsonField = from + + /** + * Returns the raw JSON value of [to]. + * + * Unlike [to], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("to") @ExcludeMissing fun _to(): JsonField = to + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [StatementPeriod]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [StatementPeriod]. */ + class Builder internal constructor() { + + private var from: JsonField = JsonMissing.of() + private var to: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(statementPeriod: StatementPeriod) = apply { + from = statementPeriod.from + to = statementPeriod.to + additionalProperties = statementPeriod.additionalProperties.toMutableMap() + } + + /** Start date of the statement period */ + fun from(from: LocalDate) = from(JsonField.of(from)) + + /** + * Sets [Builder.from] to an arbitrary JSON value. + * + * You should usually call [Builder.from] with a well-typed [LocalDate] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun from(from: JsonField) = apply { this.from = from } + + /** End date of the statement period */ + fun to(to: LocalDate) = to(JsonField.of(to)) + + /** + * Sets [Builder.to] to an arbitrary JSON value. + * + * You should usually call [Builder.to] with a well-typed [LocalDate] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun to(to: JsonField) = apply { this.to = to } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [StatementPeriod]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): StatementPeriod = + StatementPeriod(from, to, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): StatementPeriod = apply { + if (validated) { + return@apply + } + + from() + to() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (from.asKnown().isPresent) 1 else 0) + (if (to.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StatementPeriod && + from == other.from && + to == other.to && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(from, to, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "StatementPeriod{from=$from, to=$to, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Meta && + casType == other.casType && + generatedAt == other.generatedAt && + statementPeriod == other.statementPeriod && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(casType, generatedAt, statementPeriod, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Meta{casType=$casType, generatedAt=$generatedAt, statementPeriod=$statementPeriod, additionalProperties=$additionalProperties}" + } + + class MutualFund + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, private val amc: JsonField, private val folioNumber: JsonField, + private val linkedHolders: JsonField>, private val registrar: JsonField, private val schemes: JsonField>, private val value: JsonField, private val additionalProperties: MutableMap, ) { - @JsonCreator - private constructor( - @JsonProperty("additional_info") - @ExcludeMissing - additionalInfo: JsonField = JsonMissing.of(), - @JsonProperty("amc") @ExcludeMissing amc: JsonField = JsonMissing.of(), - @JsonProperty("folio_number") - @ExcludeMissing - folioNumber: JsonField = JsonMissing.of(), - @JsonProperty("registrar") - @ExcludeMissing - registrar: JsonField = JsonMissing.of(), - @JsonProperty("schemes") - @ExcludeMissing - schemes: JsonField> = JsonMissing.of(), - @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), - ) : this(additionalInfo, amc, folioNumber, registrar, schemes, value, mutableMapOf()) + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("amc") @ExcludeMissing amc: JsonField = JsonMissing.of(), + @JsonProperty("folio_number") + @ExcludeMissing + folioNumber: JsonField = JsonMissing.of(), + @JsonProperty("linked_holders") + @ExcludeMissing + linkedHolders: JsonField> = JsonMissing.of(), + @JsonProperty("registrar") + @ExcludeMissing + registrar: JsonField = JsonMissing.of(), + @JsonProperty("schemes") + @ExcludeMissing + schemes: JsonField> = JsonMissing.of(), + @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), + ) : this( + additionalInfo, + amc, + folioNumber, + linkedHolders, + registrar, + schemes, + value, + mutableMapOf(), + ) + + /** + * Additional folio information + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") + + /** + * Asset Management Company name + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun amc(): Optional = amc.getOptional("amc") + + /** + * Folio number + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun folioNumber(): Optional = folioNumber.getOptional("folio_number") + + /** + * List of account holders linked to this mutual fund folio + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun linkedHolders(): Optional> = + linkedHolders.getOptional("linked_holders") + + /** + * Registrar and Transfer Agent name + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun registrar(): Optional = registrar.getOptional("registrar") + + /** + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun schemes(): Optional> = schemes.getOptional("schemes") + + /** + * Total value of the folio + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun value(): Optional = value.getOptional("value") + + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo + + /** + * Returns the raw JSON value of [amc]. + * + * Unlike [amc], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("amc") @ExcludeMissing fun _amc(): JsonField = amc + + /** + * Returns the raw JSON value of [folioNumber]. + * + * Unlike [folioNumber], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("folio_number") + @ExcludeMissing + fun _folioNumber(): JsonField = folioNumber + + /** + * Returns the raw JSON value of [linkedHolders]. + * + * Unlike [linkedHolders], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("linked_holders") + @ExcludeMissing + fun _linkedHolders(): JsonField> = linkedHolders + + /** + * Returns the raw JSON value of [registrar]. + * + * Unlike [registrar], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("registrar") @ExcludeMissing fun _registrar(): JsonField = registrar + + /** + * Returns the raw JSON value of [schemes]. + * + * Unlike [schemes], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("schemes") @ExcludeMissing fun _schemes(): JsonField> = schemes + + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [MutualFund]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [MutualFund]. */ + class Builder internal constructor() { + + private var additionalInfo: JsonField = JsonMissing.of() + private var amc: JsonField = JsonMissing.of() + private var folioNumber: JsonField = JsonMissing.of() + private var linkedHolders: JsonField>? = null + private var registrar: JsonField = JsonMissing.of() + private var schemes: JsonField>? = null + private var value: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(mutualFund: MutualFund) = apply { + additionalInfo = mutualFund.additionalInfo + amc = mutualFund.amc + folioNumber = mutualFund.folioNumber + linkedHolders = mutualFund.linkedHolders.map { it.toMutableList() } + registrar = mutualFund.registrar + schemes = mutualFund.schemes.map { it.toMutableList() } + value = mutualFund.value + additionalProperties = mutualFund.additionalProperties.toMutableMap() + } + + /** Additional folio information */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) + + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed [AdditionalInfo] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { + this.additionalInfo = additionalInfo + } + + /** Asset Management Company name */ + fun amc(amc: String) = amc(JsonField.of(amc)) + + /** + * Sets [Builder.amc] to an arbitrary JSON value. + * + * You should usually call [Builder.amc] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun amc(amc: JsonField) = apply { this.amc = amc } + + /** Folio number */ + fun folioNumber(folioNumber: String) = folioNumber(JsonField.of(folioNumber)) + + /** + * Sets [Builder.folioNumber] to an arbitrary JSON value. + * + * You should usually call [Builder.folioNumber] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun folioNumber(folioNumber: JsonField) = apply { + this.folioNumber = folioNumber + } + + /** List of account holders linked to this mutual fund folio */ + fun linkedHolders(linkedHolders: List) = + linkedHolders(JsonField.of(linkedHolders)) + + /** + * Sets [Builder.linkedHolders] to an arbitrary JSON value. + * + * You should usually call [Builder.linkedHolders] with a well-typed + * `List` value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun linkedHolders(linkedHolders: JsonField>) = apply { + this.linkedHolders = linkedHolders.map { it.toMutableList() } + } + + /** + * Adds a single [LinkedHolder] to [linkedHolders]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addLinkedHolder(linkedHolder: LinkedHolder) = apply { + linkedHolders = + (linkedHolders ?: JsonField.of(mutableListOf())).also { + checkKnown("linkedHolders", it).add(linkedHolder) + } + } + + /** Registrar and Transfer Agent name */ + fun registrar(registrar: String) = registrar(JsonField.of(registrar)) + + /** + * Sets [Builder.registrar] to an arbitrary JSON value. + * + * You should usually call [Builder.registrar] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun registrar(registrar: JsonField) = apply { this.registrar = registrar } + + fun schemes(schemes: List) = schemes(JsonField.of(schemes)) + + /** + * Sets [Builder.schemes] to an arbitrary JSON value. + * + * You should usually call [Builder.schemes] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun schemes(schemes: JsonField>) = apply { + this.schemes = schemes.map { it.toMutableList() } + } + + /** + * Adds a single [Scheme] to [schemes]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addScheme(scheme: Scheme) = apply { + schemes = + (schemes ?: JsonField.of(mutableListOf())).also { + checkKnown("schemes", it).add(scheme) + } + } + + /** Total value of the folio */ + fun value(value: Float) = value(JsonField.of(value)) + + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [Float] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun value(value: JsonField) = apply { this.value = value } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [MutualFund]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): MutualFund = + MutualFund( + additionalInfo, + amc, + folioNumber, + (linkedHolders ?: JsonMissing.of()).map { it.toImmutable() }, + registrar, + (schemes ?: JsonMissing.of()).map { it.toImmutable() }, + value, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): MutualFund = apply { + if (validated) { + return@apply + } + + additionalInfo().ifPresent { it.validate() } + amc() + folioNumber() + linkedHolders().ifPresent { it.forEach { it.validate() } } + registrar() + schemes().ifPresent { it.forEach { it.validate() } } + value() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (amc.asKnown().isPresent) 1 else 0) + + (if (folioNumber.asKnown().isPresent) 1 else 0) + + (linkedHolders.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (registrar.asKnown().isPresent) 1 else 0) + + (schemes.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (value.asKnown().isPresent) 1 else 0) + + /** Additional folio information */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val kyc: JsonField, + private val pan: JsonField, + private val pankyc: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("kyc") @ExcludeMissing kyc: JsonField = JsonMissing.of(), + @JsonProperty("pan") @ExcludeMissing pan: JsonField = JsonMissing.of(), + @JsonProperty("pankyc") @ExcludeMissing pankyc: JsonField = JsonMissing.of(), + ) : this(kyc, pan, pankyc, mutableMapOf()) + + /** + * KYC status of the folio + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun kyc(): Optional = kyc.getOptional("kyc") + + /** + * PAN associated with the folio + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun pan(): Optional = pan.getOptional("pan") + + /** + * PAN KYC status + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun pankyc(): Optional = pankyc.getOptional("pankyc") + + /** + * Returns the raw JSON value of [kyc]. + * + * Unlike [kyc], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("kyc") @ExcludeMissing fun _kyc(): JsonField = kyc + + /** + * Returns the raw JSON value of [pan]. + * + * Unlike [pan], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pan") @ExcludeMissing fun _pan(): JsonField = pan + + /** + * Returns the raw JSON value of [pankyc]. + * + * Unlike [pankyc], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pankyc") @ExcludeMissing fun _pankyc(): JsonField = pankyc + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [AdditionalInfo]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { + + private var kyc: JsonField = JsonMissing.of() + private var pan: JsonField = JsonMissing.of() + private var pankyc: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + kyc = additionalInfo.kyc + pan = additionalInfo.pan + pankyc = additionalInfo.pankyc + additionalProperties = additionalInfo.additionalProperties.toMutableMap() + } + + /** KYC status of the folio */ + fun kyc(kyc: String) = kyc(JsonField.of(kyc)) + + /** + * Sets [Builder.kyc] to an arbitrary JSON value. + * + * You should usually call [Builder.kyc] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun kyc(kyc: JsonField) = apply { this.kyc = kyc } + + /** PAN associated with the folio */ + fun pan(pan: String) = pan(JsonField.of(pan)) + + /** + * Sets [Builder.pan] to an arbitrary JSON value. + * + * You should usually call [Builder.pan] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun pan(pan: JsonField) = apply { this.pan = pan } + + /** PAN KYC status */ + fun pankyc(pankyc: String) = pankyc(JsonField.of(pankyc)) + + /** + * Sets [Builder.pankyc] to an arbitrary JSON value. + * + * You should usually call [Builder.pankyc] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun pankyc(pankyc: JsonField) = apply { this.pankyc = pankyc } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo(kyc, pan, pankyc, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } + + kyc() + pan() + pankyc() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (kyc.asKnown().isPresent) 1 else 0) + + (if (pan.asKnown().isPresent) 1 else 0) + + (if (pankyc.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AdditionalInfo && + kyc == other.kyc && + pan == other.pan && + pankyc == other.pankyc && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(kyc, pan, pankyc, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AdditionalInfo{kyc=$kyc, pan=$pan, pankyc=$pankyc, additionalProperties=$additionalProperties}" + } + + class LinkedHolder + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val pan: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("pan") @ExcludeMissing pan: JsonField = JsonMissing.of(), + ) : this(name, pan, mutableMapOf()) + + /** + * Name of the account holder + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * PAN of the account holder + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun pan(): Optional = pan.getOptional("pan") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [pan]. + * + * Unlike [pan], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pan") @ExcludeMissing fun _pan(): JsonField = pan + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [LinkedHolder]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [LinkedHolder]. */ + class Builder internal constructor() { + + private var name: JsonField = JsonMissing.of() + private var pan: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(linkedHolder: LinkedHolder) = apply { + name = linkedHolder.name + pan = linkedHolder.pan + additionalProperties = linkedHolder.additionalProperties.toMutableMap() + } + + /** Name of the account holder */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** PAN of the account holder */ + fun pan(pan: String) = pan(JsonField.of(pan)) + + /** + * Sets [Builder.pan] to an arbitrary JSON value. + * + * You should usually call [Builder.pan] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun pan(pan: JsonField) = apply { this.pan = pan } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [LinkedHolder]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): LinkedHolder = + LinkedHolder(name, pan, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): LinkedHolder = apply { + if (validated) { + return@apply + } + + name() + pan() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (name.asKnown().isPresent) 1 else 0) + (if (pan.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is LinkedHolder && + name == other.name && + pan == other.pan && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(name, pan, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "LinkedHolder{name=$name, pan=$pan, additionalProperties=$additionalProperties}" + } + + class Scheme + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, + private val cost: JsonField, + private val gain: JsonField, + private val isin: JsonField, + private val name: JsonField, + private val nav: JsonField, + private val nominees: JsonField>, + private val transactions: JsonField>, + private val type: JsonField, + private val units: JsonField, + private val value: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("cost") @ExcludeMissing cost: JsonField = JsonMissing.of(), + @JsonProperty("gain") @ExcludeMissing gain: JsonField = JsonMissing.of(), + @JsonProperty("isin") @ExcludeMissing isin: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("nav") @ExcludeMissing nav: JsonField = JsonMissing.of(), + @JsonProperty("nominees") + @ExcludeMissing + nominees: JsonField> = JsonMissing.of(), + @JsonProperty("transactions") + @ExcludeMissing + transactions: JsonField> = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("units") @ExcludeMissing units: JsonField = JsonMissing.of(), + @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), + ) : this( + additionalInfo, + cost, + gain, + isin, + name, + nav, + nominees, + transactions, + type, + units, + value, + mutableMapOf(), + ) + + /** + * Additional information specific to the scheme + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") + + /** + * Cost of investment + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun cost(): Optional = cost.getOptional("cost") + + /** + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun gain(): Optional = gain.getOptional("gain") + + /** + * ISIN code of the scheme + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun isin(): Optional = isin.getOptional("isin") + + /** + * Scheme name + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * Net Asset Value per unit + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun nav(): Optional = nav.getOptional("nav") + + /** + * List of nominees + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun nominees(): Optional> = nominees.getOptional("nominees") + + /** + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun transactions(): Optional> = + transactions.getOptional("transactions") + + /** + * Type of mutual fund scheme + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") + + /** + * Number of units held + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun units(): Optional = units.getOptional("units") + + /** + * Current market value of the holding + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun value(): Optional = value.getOptional("value") + + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo + + /** + * Returns the raw JSON value of [cost]. + * + * Unlike [cost], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cost") @ExcludeMissing fun _cost(): JsonField = cost + + /** + * Returns the raw JSON value of [gain]. + * + * Unlike [gain], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("gain") @ExcludeMissing fun _gain(): JsonField = gain + + /** + * Returns the raw JSON value of [isin]. + * + * Unlike [isin], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("isin") @ExcludeMissing fun _isin(): JsonField = isin + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [nav]. + * + * Unlike [nav], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("nav") @ExcludeMissing fun _nav(): JsonField = nav + + /** + * Returns the raw JSON value of [nominees]. + * + * Unlike [nominees], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("nominees") + @ExcludeMissing + fun _nominees(): JsonField> = nominees + + /** + * Returns the raw JSON value of [transactions]. + * + * Unlike [transactions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("transactions") + @ExcludeMissing + fun _transactions(): JsonField> = transactions + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [units]. + * + * Unlike [units], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units + + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Scheme]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Scheme]. */ + class Builder internal constructor() { + + private var additionalInfo: JsonField = JsonMissing.of() + private var cost: JsonField = JsonMissing.of() + private var gain: JsonField = JsonMissing.of() + private var isin: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var nav: JsonField = JsonMissing.of() + private var nominees: JsonField>? = null + private var transactions: JsonField>? = null + private var type: JsonField = JsonMissing.of() + private var units: JsonField = JsonMissing.of() + private var value: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(scheme: Scheme) = apply { + additionalInfo = scheme.additionalInfo + cost = scheme.cost + gain = scheme.gain + isin = scheme.isin + name = scheme.name + nav = scheme.nav + nominees = scheme.nominees.map { it.toMutableList() } + transactions = scheme.transactions.map { it.toMutableList() } + type = scheme.type + units = scheme.units + value = scheme.value + additionalProperties = scheme.additionalProperties.toMutableMap() + } + + /** Additional information specific to the scheme */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) + + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { + this.additionalInfo = additionalInfo + } + + /** Cost of investment */ + fun cost(cost: Float) = cost(JsonField.of(cost)) + + /** + * Sets [Builder.cost] to an arbitrary JSON value. + * + * You should usually call [Builder.cost] with a well-typed [Float] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun cost(cost: JsonField) = apply { this.cost = cost } + + fun gain(gain: Gain) = gain(JsonField.of(gain)) + + /** + * Sets [Builder.gain] to an arbitrary JSON value. + * + * You should usually call [Builder.gain] with a well-typed [Gain] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun gain(gain: JsonField) = apply { this.gain = gain } + + /** ISIN code of the scheme */ + fun isin(isin: String) = isin(JsonField.of(isin)) + + /** + * Sets [Builder.isin] to an arbitrary JSON value. + * + * You should usually call [Builder.isin] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isin(isin: JsonField) = apply { this.isin = isin } + + /** Scheme name */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Net Asset Value per unit */ + fun nav(nav: Float) = nav(JsonField.of(nav)) + + /** + * Sets [Builder.nav] to an arbitrary JSON value. + * + * You should usually call [Builder.nav] with a well-typed [Float] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun nav(nav: JsonField) = apply { this.nav = nav } + + /** List of nominees */ + fun nominees(nominees: List) = nominees(JsonField.of(nominees)) + + /** + * Sets [Builder.nominees] to an arbitrary JSON value. + * + * You should usually call [Builder.nominees] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun nominees(nominees: JsonField>) = apply { + this.nominees = nominees.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [nominees]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addNominee(nominee: String) = apply { + nominees = + (nominees ?: JsonField.of(mutableListOf())).also { + checkKnown("nominees", it).add(nominee) + } + } + + fun transactions(transactions: List) = + transactions(JsonField.of(transactions)) + + /** + * Sets [Builder.transactions] to an arbitrary JSON value. + * + * You should usually call [Builder.transactions] with a well-typed + * `List` value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun transactions(transactions: JsonField>) = apply { + this.transactions = transactions.map { it.toMutableList() } + } + + /** + * Adds a single [Transaction] to [transactions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTransaction(transaction: Transaction) = apply { + transactions = + (transactions ?: JsonField.of(mutableListOf())).also { + checkKnown("transactions", it).add(transaction) + } + } + + /** Type of mutual fund scheme */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + /** Number of units held */ + fun units(units: Float) = units(JsonField.of(units)) + + /** + * Sets [Builder.units] to an arbitrary JSON value. + * + * You should usually call [Builder.units] with a well-typed [Float] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun units(units: JsonField) = apply { this.units = units } + + /** Current market value of the holding */ + fun value(value: Float) = value(JsonField.of(value)) + + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [Float] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun value(value: JsonField) = apply { this.value = value } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Scheme]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Scheme = + Scheme( + additionalInfo, + cost, + gain, + isin, + name, + nav, + (nominees ?: JsonMissing.of()).map { it.toImmutable() }, + (transactions ?: JsonMissing.of()).map { it.toImmutable() }, + type, + units, + value, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Scheme = apply { + if (validated) { + return@apply + } + + additionalInfo().ifPresent { it.validate() } + cost() + gain().ifPresent { it.validate() } + isin() + name() + nav() + nominees() + transactions().ifPresent { it.forEach { it.validate() } } + type().ifPresent { it.validate() } + units() + value() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (cost.asKnown().isPresent) 1 else 0) + + (gain.asKnown().getOrNull()?.validity() ?: 0) + + (if (isin.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (nav.asKnown().isPresent) 1 else 0) + + (nominees.asKnown().getOrNull()?.size ?: 0) + + (transactions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (units.asKnown().isPresent) 1 else 0) + + (if (value.asKnown().isPresent) 1 else 0) + + /** Additional information specific to the scheme */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val advisor: JsonField, + private val amfi: JsonField, + private val closeUnits: JsonField, + private val openUnits: JsonField, + private val rtaCode: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("advisor") + @ExcludeMissing + advisor: JsonField = JsonMissing.of(), + @JsonProperty("amfi") + @ExcludeMissing + amfi: JsonField = JsonMissing.of(), + @JsonProperty("close_units") + @ExcludeMissing + closeUnits: JsonField = JsonMissing.of(), + @JsonProperty("open_units") + @ExcludeMissing + openUnits: JsonField = JsonMissing.of(), + @JsonProperty("rta_code") + @ExcludeMissing + rtaCode: JsonField = JsonMissing.of(), + ) : this(advisor, amfi, closeUnits, openUnits, rtaCode, mutableMapOf()) + + /** + * Financial advisor name (CAMS/KFintech) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun advisor(): Optional = advisor.getOptional("advisor") + + /** + * AMFI code for the scheme (CAMS/KFintech) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun amfi(): Optional = amfi.getOptional("amfi") + + /** + * Closing balance units for the statement period + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun closeUnits(): Optional = closeUnits.getOptional("close_units") + + /** + * Opening balance units for the statement period + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun openUnits(): Optional = openUnits.getOptional("open_units") + + /** + * RTA code for the scheme (CAMS/KFintech) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun rtaCode(): Optional = rtaCode.getOptional("rta_code") + + /** + * Returns the raw JSON value of [advisor]. + * + * Unlike [advisor], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("advisor") @ExcludeMissing fun _advisor(): JsonField = advisor + + /** + * Returns the raw JSON value of [amfi]. + * + * Unlike [amfi], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("amfi") @ExcludeMissing fun _amfi(): JsonField = amfi + + /** + * Returns the raw JSON value of [closeUnits]. + * + * Unlike [closeUnits], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("close_units") + @ExcludeMissing + fun _closeUnits(): JsonField = closeUnits + + /** + * Returns the raw JSON value of [openUnits]. + * + * Unlike [openUnits], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("open_units") + @ExcludeMissing + fun _openUnits(): JsonField = openUnits + + /** + * Returns the raw JSON value of [rtaCode]. + * + * Unlike [rtaCode], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("rta_code") + @ExcludeMissing + fun _rtaCode(): JsonField = rtaCode + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { + + private var advisor: JsonField = JsonMissing.of() + private var amfi: JsonField = JsonMissing.of() + private var closeUnits: JsonField = JsonMissing.of() + private var openUnits: JsonField = JsonMissing.of() + private var rtaCode: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + advisor = additionalInfo.advisor + amfi = additionalInfo.amfi + closeUnits = additionalInfo.closeUnits + openUnits = additionalInfo.openUnits + rtaCode = additionalInfo.rtaCode + additionalProperties = additionalInfo.additionalProperties.toMutableMap() + } + + /** Financial advisor name (CAMS/KFintech) */ + fun advisor(advisor: String) = advisor(JsonField.of(advisor)) + + /** + * Sets [Builder.advisor] to an arbitrary JSON value. + * + * You should usually call [Builder.advisor] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun advisor(advisor: JsonField) = apply { this.advisor = advisor } + + /** AMFI code for the scheme (CAMS/KFintech) */ + fun amfi(amfi: String) = amfi(JsonField.of(amfi)) + + /** + * Sets [Builder.amfi] to an arbitrary JSON value. + * + * You should usually call [Builder.amfi] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun amfi(amfi: JsonField) = apply { this.amfi = amfi } + + /** Closing balance units for the statement period */ + fun closeUnits(closeUnits: Float?) = + closeUnits(JsonField.ofNullable(closeUnits)) + + /** + * Alias for [Builder.closeUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun closeUnits(closeUnits: Float) = closeUnits(closeUnits as Float?) + + /** Alias for calling [Builder.closeUnits] with `closeUnits.orElse(null)`. */ + fun closeUnits(closeUnits: Optional) = closeUnits(closeUnits.getOrNull()) + + /** + * Sets [Builder.closeUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.closeUnits] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun closeUnits(closeUnits: JsonField) = apply { + this.closeUnits = closeUnits + } + + /** Opening balance units for the statement period */ + fun openUnits(openUnits: Float?) = openUnits(JsonField.ofNullable(openUnits)) + + /** + * Alias for [Builder.openUnits]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun openUnits(openUnits: Float) = openUnits(openUnits as Float?) + + /** Alias for calling [Builder.openUnits] with `openUnits.orElse(null)`. */ + fun openUnits(openUnits: Optional) = openUnits(openUnits.getOrNull()) + + /** + * Sets [Builder.openUnits] to an arbitrary JSON value. + * + * You should usually call [Builder.openUnits] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun openUnits(openUnits: JsonField) = apply { + this.openUnits = openUnits + } + + /** RTA code for the scheme (CAMS/KFintech) */ + fun rtaCode(rtaCode: String) = rtaCode(JsonField.of(rtaCode)) + + /** + * Sets [Builder.rtaCode] to an arbitrary JSON value. + * + * You should usually call [Builder.rtaCode] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun rtaCode(rtaCode: JsonField) = apply { this.rtaCode = rtaCode } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + advisor, + amfi, + closeUnits, + openUnits, + rtaCode, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } + + advisor() + amfi() + closeUnits() + openUnits() + rtaCode() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (advisor.asKnown().isPresent) 1 else 0) + + (if (amfi.asKnown().isPresent) 1 else 0) + + (if (closeUnits.asKnown().isPresent) 1 else 0) + + (if (openUnits.asKnown().isPresent) 1 else 0) + + (if (rtaCode.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AdditionalInfo && + advisor == other.advisor && + amfi == other.amfi && + closeUnits == other.closeUnits && + openUnits == other.openUnits && + rtaCode == other.rtaCode && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + advisor, + amfi, + closeUnits, + openUnits, + rtaCode, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AdditionalInfo{advisor=$advisor, amfi=$amfi, closeUnits=$closeUnits, openUnits=$openUnits, rtaCode=$rtaCode, additionalProperties=$additionalProperties}" + } + + class Gain + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val absolute: JsonField, + private val percentage: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("absolute") + @ExcludeMissing + absolute: JsonField = JsonMissing.of(), + @JsonProperty("percentage") + @ExcludeMissing + percentage: JsonField = JsonMissing.of(), + ) : this(absolute, percentage, mutableMapOf()) + + /** + * Absolute gain or loss + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun absolute(): Optional = absolute.getOptional("absolute") + + /** + * Percentage gain or loss + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun percentage(): Optional = percentage.getOptional("percentage") + + /** + * Returns the raw JSON value of [absolute]. + * + * Unlike [absolute], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("absolute") + @ExcludeMissing + fun _absolute(): JsonField = absolute + + /** + * Returns the raw JSON value of [percentage]. + * + * Unlike [percentage], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("percentage") + @ExcludeMissing + fun _percentage(): JsonField = percentage + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Gain]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Gain]. */ + class Builder internal constructor() { + + private var absolute: JsonField = JsonMissing.of() + private var percentage: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(gain: Gain) = apply { + absolute = gain.absolute + percentage = gain.percentage + additionalProperties = gain.additionalProperties.toMutableMap() + } - /** - * Additional folio information - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun additionalInfo(): Optional = - additionalInfo.getOptional("additional_info") + /** Absolute gain or loss */ + fun absolute(absolute: Float) = absolute(JsonField.of(absolute)) - /** - * Asset Management Company name - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun amc(): Optional = amc.getOptional("amc") + /** + * Sets [Builder.absolute] to an arbitrary JSON value. + * + * You should usually call [Builder.absolute] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun absolute(absolute: JsonField) = apply { this.absolute = absolute } - /** - * Folio number - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun folioNumber(): Optional = folioNumber.getOptional("folio_number") + /** Percentage gain or loss */ + fun percentage(percentage: Float) = percentage(JsonField.of(percentage)) - /** - * Registrar and Transfer Agent name - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun registrar(): Optional = registrar.getOptional("registrar") + /** + * Sets [Builder.percentage] to an arbitrary JSON value. + * + * You should usually call [Builder.percentage] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun percentage(percentage: JsonField) = apply { + this.percentage = percentage + } - /** - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun schemes(): Optional> = schemes.getOptional("schemes") + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - /** - * Total value of the folio - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun value(): Optional = value.getOptional("value") + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - /** - * Returns the raw JSON value of [additionalInfo]. - * - * Unlike [additionalInfo], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("additional_info") - @ExcludeMissing - fun _additionalInfo(): JsonField = additionalInfo + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } - /** - * Returns the raw JSON value of [amc]. - * - * Unlike [amc], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("amc") @ExcludeMissing fun _amc(): JsonField = amc + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - /** - * Returns the raw JSON value of [folioNumber]. - * - * Unlike [folioNumber], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("folio_number") - @ExcludeMissing - fun _folioNumber(): JsonField = folioNumber + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - /** - * Returns the raw JSON value of [registrar]. - * - * Unlike [registrar], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("registrar") @ExcludeMissing fun _registrar(): JsonField = registrar + /** + * Returns an immutable instance of [Gain]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Gain = + Gain(absolute, percentage, additionalProperties.toMutableMap()) + } - /** - * Returns the raw JSON value of [schemes]. - * - * Unlike [schemes], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("schemes") @ExcludeMissing fun _schemes(): JsonField> = schemes + private var validated: Boolean = false - /** - * Returns the raw JSON value of [value]. - * - * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value + fun validate(): Gain = apply { + if (validated) { + return@apply + } - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + absolute() + percentage() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (absolute.asKnown().isPresent) 1 else 0) + + (if (percentage.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Gain && + absolute == other.absolute && + percentage == other.percentage && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(absolute, percentage, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Gain{absolute=$absolute, percentage=$percentage, additionalProperties=$additionalProperties}" + } + + /** + * Unified transaction schema for all holding types (MF folios, equities, bonds, etc.) + */ + class Transaction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, + private val amount: JsonField, + private val balance: JsonField, + private val date: JsonField, + private val description: JsonField, + private val dividendRate: JsonField, + private val nav: JsonField, + private val type: JsonField, + private val units: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("amount") + @ExcludeMissing + amount: JsonField = JsonMissing.of(), + @JsonProperty("balance") + @ExcludeMissing + balance: JsonField = JsonMissing.of(), + @JsonProperty("date") + @ExcludeMissing + date: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("dividend_rate") + @ExcludeMissing + dividendRate: JsonField = JsonMissing.of(), + @JsonProperty("nav") @ExcludeMissing nav: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("units") + @ExcludeMissing + units: JsonField = JsonMissing.of(), + ) : this( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + mutableMapOf(), + ) - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + /** + * Additional transaction-specific fields that vary by source + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") - fun toBuilder() = Builder().from(this) + /** + * Transaction amount in currency (computed from units × price/NAV) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun amount(): Optional = amount.getOptional("amount") - companion object { + /** + * Balance units after transaction + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun balance(): Optional = balance.getOptional("balance") - /** Returns a mutable builder for constructing an instance of [MutualFund]. */ - @JvmStatic fun builder() = Builder() - } + /** + * Transaction date (YYYY-MM-DD) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun date(): Optional = date.getOptional("date") - /** A builder for [MutualFund]. */ - class Builder internal constructor() { + /** + * Transaction description/particulars + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun description(): Optional = description.getOptional("description") - private var additionalInfo: JsonField = JsonMissing.of() - private var amc: JsonField = JsonMissing.of() - private var folioNumber: JsonField = JsonMissing.of() - private var registrar: JsonField = JsonMissing.of() - private var schemes: JsonField>? = null - private var value: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + /** + * Dividend rate (for DIVIDEND_PAYOUT transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun dividendRate(): Optional = dividendRate.getOptional("dividend_rate") - @JvmSynthetic - internal fun from(mutualFund: MutualFund) = apply { - additionalInfo = mutualFund.additionalInfo - amc = mutualFund.amc - folioNumber = mutualFund.folioNumber - registrar = mutualFund.registrar - schemes = mutualFund.schemes.map { it.toMutableList() } - value = mutualFund.value - additionalProperties = mutualFund.additionalProperties.toMutableMap() - } + /** + * NAV/price per unit on transaction date + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun nav(): Optional = nav.getOptional("nav") - /** Additional folio information */ - fun additionalInfo(additionalInfo: AdditionalInfo) = - additionalInfo(JsonField.of(additionalInfo)) + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, REVERSAL, + * UNKNOWN. + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") - /** - * Sets [Builder.additionalInfo] to an arbitrary JSON value. - * - * You should usually call [Builder.additionalInfo] with a well-typed [AdditionalInfo] - * value instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun additionalInfo(additionalInfo: JsonField) = apply { - this.additionalInfo = additionalInfo - } + /** + * Number of units involved in transaction + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun units(): Optional = units.getOptional("units") - /** Asset Management Company name */ - fun amc(amc: String) = amc(JsonField.of(amc)) + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo - /** - * Sets [Builder.amc] to an arbitrary JSON value. - * - * You should usually call [Builder.amc] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun amc(amc: JsonField) = apply { this.amc = amc } + /** + * Returns the raw JSON value of [amount]. + * + * Unlike [amount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("amount") @ExcludeMissing fun _amount(): JsonField = amount - /** Folio number */ - fun folioNumber(folioNumber: String) = folioNumber(JsonField.of(folioNumber)) + /** + * Returns the raw JSON value of [balance]. + * + * Unlike [balance], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("balance") @ExcludeMissing fun _balance(): JsonField = balance - /** - * Sets [Builder.folioNumber] to an arbitrary JSON value. - * - * You should usually call [Builder.folioNumber] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun folioNumber(folioNumber: JsonField) = apply { - this.folioNumber = folioNumber - } + /** + * Returns the raw JSON value of [date]. + * + * Unlike [date], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("date") @ExcludeMissing fun _date(): JsonField = date - /** Registrar and Transfer Agent name */ - fun registrar(registrar: String) = registrar(JsonField.of(registrar)) + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description - /** - * Sets [Builder.registrar] to an arbitrary JSON value. - * - * You should usually call [Builder.registrar] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun registrar(registrar: JsonField) = apply { this.registrar = registrar } + /** + * Returns the raw JSON value of [dividendRate]. + * + * Unlike [dividendRate], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("dividend_rate") + @ExcludeMissing + fun _dividendRate(): JsonField = dividendRate - fun schemes(schemes: List) = schemes(JsonField.of(schemes)) + /** + * Returns the raw JSON value of [nav]. + * + * Unlike [nav], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("nav") @ExcludeMissing fun _nav(): JsonField = nav - /** - * Sets [Builder.schemes] to an arbitrary JSON value. - * - * You should usually call [Builder.schemes] with a well-typed `List` value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun schemes(schemes: JsonField>) = apply { - this.schemes = schemes.map { it.toMutableList() } - } + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type - /** - * Adds a single [Scheme] to [schemes]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addScheme(scheme: Scheme) = apply { - schemes = - (schemes ?: JsonField.of(mutableListOf())).also { - checkKnown("schemes", it).add(scheme) - } - } + /** + * Returns the raw JSON value of [units]. + * + * Unlike [units], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units - /** Total value of the folio */ - fun value(value: Float) = value(JsonField.of(value)) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - /** - * Sets [Builder.value] to an arbitrary JSON value. - * - * You should usually call [Builder.value] with a well-typed [Float] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun value(value: JsonField) = apply { this.value = value } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + fun toBuilder() = Builder().from(this) - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + companion object { - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + /** Returns a mutable builder for constructing an instance of [Transaction]. */ + @JvmStatic fun builder() = Builder() + } - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + /** A builder for [Transaction]. */ + class Builder internal constructor() { - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + private var additionalInfo: JsonField = JsonMissing.of() + private var amount: JsonField = JsonMissing.of() + private var balance: JsonField = JsonMissing.of() + private var date: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var dividendRate: JsonField = JsonMissing.of() + private var nav: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var units: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** - * Returns an immutable instance of [MutualFund]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): MutualFund = - MutualFund( - additionalInfo, - amc, - folioNumber, - registrar, - (schemes ?: JsonMissing.of()).map { it.toImmutable() }, - value, - additionalProperties.toMutableMap(), - ) - } + @JvmSynthetic + internal fun from(transaction: Transaction) = apply { + additionalInfo = transaction.additionalInfo + amount = transaction.amount + balance = transaction.balance + date = transaction.date + description = transaction.description + dividendRate = transaction.dividendRate + nav = transaction.nav + type = transaction.type + units = transaction.units + additionalProperties = transaction.additionalProperties.toMutableMap() + } - private var validated: Boolean = false + /** Additional transaction-specific fields that vary by source */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) - fun validate(): MutualFund = apply { - if (validated) { - return@apply - } + /** + * Sets [Builder.additionalInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun additionalInfo(additionalInfo: JsonField) = apply { + this.additionalInfo = additionalInfo + } - additionalInfo().ifPresent { it.validate() } - amc() - folioNumber() - registrar() - schemes().ifPresent { it.forEach { it.validate() } } - value() - validated = true - } + /** Transaction amount in currency (computed from units × price/NAV) */ + fun amount(amount: Float?) = amount(JsonField.ofNullable(amount)) - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + /** + * Alias for [Builder.amount]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun amount(amount: Float) = amount(amount as Float?) - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + - (if (amc.asKnown().isPresent) 1 else 0) + - (if (folioNumber.asKnown().isPresent) 1 else 0) + - (if (registrar.asKnown().isPresent) 1 else 0) + - (schemes.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + - (if (value.asKnown().isPresent) 1 else 0) + /** Alias for calling [Builder.amount] with `amount.orElse(null)`. */ + fun amount(amount: Optional) = amount(amount.getOrNull()) - /** Additional folio information */ - class AdditionalInfo - private constructor( - private val kyc: JsonField, - private val pan: JsonField, - private val pankyc: JsonField, - private val additionalProperties: MutableMap, - ) { + /** + * Sets [Builder.amount] to an arbitrary JSON value. + * + * You should usually call [Builder.amount] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun amount(amount: JsonField) = apply { this.amount = amount } - @JsonCreator - private constructor( - @JsonProperty("kyc") @ExcludeMissing kyc: JsonField = JsonMissing.of(), - @JsonProperty("pan") @ExcludeMissing pan: JsonField = JsonMissing.of(), - @JsonProperty("pankyc") @ExcludeMissing pankyc: JsonField = JsonMissing.of(), - ) : this(kyc, pan, pankyc, mutableMapOf()) + /** Balance units after transaction */ + fun balance(balance: Float) = balance(JsonField.of(balance)) - /** - * KYC status of the folio - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun kyc(): Optional = kyc.getOptional("kyc") + /** + * Sets [Builder.balance] to an arbitrary JSON value. + * + * You should usually call [Builder.balance] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun balance(balance: JsonField) = apply { this.balance = balance } - /** - * PAN associated with the folio - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun pan(): Optional = pan.getOptional("pan") + /** Transaction date (YYYY-MM-DD) */ + fun date(date: LocalDate) = date(JsonField.of(date)) - /** - * PAN KYC status - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun pankyc(): Optional = pankyc.getOptional("pankyc") + /** + * Sets [Builder.date] to an arbitrary JSON value. + * + * You should usually call [Builder.date] with a well-typed [LocalDate] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun date(date: JsonField) = apply { this.date = date } - /** - * Returns the raw JSON value of [kyc]. - * - * Unlike [kyc], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("kyc") @ExcludeMissing fun _kyc(): JsonField = kyc + /** Transaction description/particulars */ + fun description(description: String) = description(JsonField.of(description)) - /** - * Returns the raw JSON value of [pan]. - * - * Unlike [pan], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("pan") @ExcludeMissing fun _pan(): JsonField = pan + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } - /** - * Returns the raw JSON value of [pankyc]. - * - * Unlike [pankyc], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("pankyc") @ExcludeMissing fun _pankyc(): JsonField = pankyc + /** Dividend rate (for DIVIDEND_PAYOUT transactions) */ + fun dividendRate(dividendRate: Float?) = + dividendRate(JsonField.ofNullable(dividendRate)) - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + /** + * Alias for [Builder.dividendRate]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun dividendRate(dividendRate: Float) = dividendRate(dividendRate as Float?) - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + /** + * Alias for calling [Builder.dividendRate] with `dividendRate.orElse(null)`. + */ + fun dividendRate(dividendRate: Optional) = + dividendRate(dividendRate.getOrNull()) - fun toBuilder() = Builder().from(this) + /** + * Sets [Builder.dividendRate] to an arbitrary JSON value. + * + * You should usually call [Builder.dividendRate] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun dividendRate(dividendRate: JsonField) = apply { + this.dividendRate = dividendRate + } - companion object { + /** NAV/price per unit on transaction date */ + fun nav(nav: Float?) = nav(JsonField.ofNullable(nav)) - /** Returns a mutable builder for constructing an instance of [AdditionalInfo]. */ - @JvmStatic fun builder() = Builder() - } + /** + * Alias for [Builder.nav]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun nav(nav: Float) = nav(nav as Float?) - /** A builder for [AdditionalInfo]. */ - class Builder internal constructor() { + /** Alias for calling [Builder.nav] with `nav.orElse(null)`. */ + fun nav(nav: Optional) = nav(nav.getOrNull()) - private var kyc: JsonField = JsonMissing.of() - private var pan: JsonField = JsonMissing.of() - private var pankyc: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + /** + * Sets [Builder.nav] to an arbitrary JSON value. + * + * You should usually call [Builder.nav] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun nav(nav: JsonField) = apply { this.nav = nav } - @JvmSynthetic - internal fun from(additionalInfo: AdditionalInfo) = apply { - kyc = additionalInfo.kyc - pan = additionalInfo.pan - pankyc = additionalInfo.pankyc - additionalProperties = additionalInfo.additionalProperties.toMutableMap() - } + /** + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, + * REVERSAL, UNKNOWN. + */ + fun type(type: Type) = type(JsonField.of(type)) - /** KYC status of the folio */ - fun kyc(kyc: String) = kyc(JsonField.of(kyc)) + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } - /** - * Sets [Builder.kyc] to an arbitrary JSON value. - * - * You should usually call [Builder.kyc] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun kyc(kyc: JsonField) = apply { this.kyc = kyc } + /** Number of units involved in transaction */ + fun units(units: Float) = units(JsonField.of(units)) - /** PAN associated with the folio */ - fun pan(pan: String) = pan(JsonField.of(pan)) + /** + * Sets [Builder.units] to an arbitrary JSON value. + * + * You should usually call [Builder.units] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun units(units: JsonField) = apply { this.units = units } - /** - * Sets [Builder.pan] to an arbitrary JSON value. - * - * You should usually call [Builder.pan] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun pan(pan: JsonField) = apply { this.pan = pan } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - /** PAN KYC status */ - fun pankyc(pankyc: String) = pankyc(JsonField.of(pankyc)) + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - /** - * Sets [Builder.pankyc] to an arbitrary JSON value. - * - * You should usually call [Builder.pankyc] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun pankyc(pankyc: JsonField) = apply { this.pankyc = pankyc } + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Transaction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Transaction = + Transaction( + additionalInfo, + amount, + balance, + date, + description, + dividendRate, + nav, + type, + units, + additionalProperties.toMutableMap(), + ) } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) + private var validated: Boolean = false + + fun validate(): Transaction = apply { + if (validated) { + return@apply } - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) + additionalInfo().ifPresent { it.validate() } + amount() + balance() + date() + description() + dividendRate() + nav() + type().ifPresent { it.validate() } + units() + validated = true } - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } /** - * Returns an immutable instance of [AdditionalInfo]. + * Returns a score indicating how many valid values are contained in this object + * recursively. * - * Further updates to this [Builder] will not mutate the returned instance. + * Used for best match union deserialization. */ - fun build(): AdditionalInfo = - AdditionalInfo(kyc, pan, pankyc, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): AdditionalInfo = apply { - if (validated) { - return@apply - } - - kyc() - pan() - pankyc() - validated = true - } + @JvmSynthetic + internal fun validity(): Int = + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (amount.asKnown().isPresent) 1 else 0) + + (if (balance.asKnown().isPresent) 1 else 0) + + (if (date.asKnown().isPresent) 1 else 0) + + (if (description.asKnown().isPresent) 1 else 0) + + (if (dividendRate.asKnown().isPresent) 1 else 0) + + (if (nav.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (units.asKnown().isPresent) 1 else 0) - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + /** Additional transaction-specific fields that vary by source */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val capitalWithdrawal: JsonField, + private val credit: JsonField, + private val debit: JsonField, + private val incomeDistribution: JsonField, + private val orderNo: JsonField, + private val price: JsonField, + private val stampDuty: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("capital_withdrawal") + @ExcludeMissing + capitalWithdrawal: JsonField = JsonMissing.of(), + @JsonProperty("credit") + @ExcludeMissing + credit: JsonField = JsonMissing.of(), + @JsonProperty("debit") + @ExcludeMissing + debit: JsonField = JsonMissing.of(), + @JsonProperty("income_distribution") + @ExcludeMissing + incomeDistribution: JsonField = JsonMissing.of(), + @JsonProperty("order_no") + @ExcludeMissing + orderNo: JsonField = JsonMissing.of(), + @JsonProperty("price") + @ExcludeMissing + price: JsonField = JsonMissing.of(), + @JsonProperty("stamp_duty") + @ExcludeMissing + stampDuty: JsonField = JsonMissing.of(), + ) : this( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + mutableMapOf(), + ) - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (kyc.asKnown().isPresent) 1 else 0) + - (if (pan.asKnown().isPresent) 1 else 0) + - (if (pankyc.asKnown().isPresent) 1 else 0) + /** + * Capital withdrawal amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun capitalWithdrawal(): Optional = + capitalWithdrawal.getOptional("capital_withdrawal") - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Units credited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun credit(): Optional = credit.getOptional("credit") - return other is AdditionalInfo && - kyc == other.kyc && - pan == other.pan && - pankyc == other.pankyc && - additionalProperties == other.additionalProperties - } + /** + * Units debited (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun debit(): Optional = debit.getOptional("debit") - private val hashCode: Int by lazy { - Objects.hash(kyc, pan, pankyc, additionalProperties) - } + /** + * Income distribution amount (CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun incomeDistribution(): Optional = + incomeDistribution.getOptional("income_distribution") - override fun hashCode(): Int = hashCode + /** + * Order/transaction reference number (demat transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun orderNo(): Optional = orderNo.getOptional("order_no") - override fun toString() = - "AdditionalInfo{kyc=$kyc, pan=$pan, pankyc=$pankyc, additionalProperties=$additionalProperties}" - } + /** + * Price per unit (NSDL/CDSL MF transactions) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun price(): Optional = price.getOptional("price") - class Scheme - private constructor( - private val additionalInfo: JsonField, - private val cost: JsonField, - private val gain: JsonField, - private val isin: JsonField, - private val name: JsonField, - private val nav: JsonField, - private val nominees: JsonField>, - private val transactions: JsonField>, - private val type: JsonField, - private val units: JsonField, - private val value: JsonField, - private val additionalProperties: MutableMap, - ) { + /** + * Stamp duty charged + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun stampDuty(): Optional = stampDuty.getOptional("stamp_duty") - @JsonCreator - private constructor( - @JsonProperty("additional_info") - @ExcludeMissing - additionalInfo: JsonField = JsonMissing.of(), - @JsonProperty("cost") @ExcludeMissing cost: JsonField = JsonMissing.of(), - @JsonProperty("gain") @ExcludeMissing gain: JsonField = JsonMissing.of(), - @JsonProperty("isin") @ExcludeMissing isin: JsonField = JsonMissing.of(), - @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), - @JsonProperty("nav") @ExcludeMissing nav: JsonField = JsonMissing.of(), - @JsonProperty("nominees") - @ExcludeMissing - nominees: JsonField> = JsonMissing.of(), - @JsonProperty("transactions") - @ExcludeMissing - transactions: JsonField> = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), - @JsonProperty("units") @ExcludeMissing units: JsonField = JsonMissing.of(), - @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), - ) : this( - additionalInfo, - cost, - gain, - isin, - name, - nav, - nominees, - transactions, - type, - units, - value, - mutableMapOf(), - ) + /** + * Returns the raw JSON value of [capitalWithdrawal]. + * + * Unlike [capitalWithdrawal], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("capital_withdrawal") + @ExcludeMissing + fun _capitalWithdrawal(): JsonField = capitalWithdrawal - /** - * Additional information specific to the scheme - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun additionalInfo(): Optional = - additionalInfo.getOptional("additional_info") + /** + * Returns the raw JSON value of [credit]. + * + * Unlike [credit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("credit") @ExcludeMissing fun _credit(): JsonField = credit - /** - * Cost of investment - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun cost(): Optional = cost.getOptional("cost") + /** + * Returns the raw JSON value of [debit]. + * + * Unlike [debit], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("debit") @ExcludeMissing fun _debit(): JsonField = debit - /** - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun gain(): Optional = gain.getOptional("gain") + /** + * Returns the raw JSON value of [incomeDistribution]. + * + * Unlike [incomeDistribution], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("income_distribution") + @ExcludeMissing + fun _incomeDistribution(): JsonField = incomeDistribution - /** - * ISIN code of the scheme - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun isin(): Optional = isin.getOptional("isin") + /** + * Returns the raw JSON value of [orderNo]. + * + * Unlike [orderNo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("order_no") + @ExcludeMissing + fun _orderNo(): JsonField = orderNo - /** - * Scheme name - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun name(): Optional = name.getOptional("name") + /** + * Returns the raw JSON value of [price]. + * + * Unlike [price], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("price") @ExcludeMissing fun _price(): JsonField = price - /** - * Net Asset Value per unit - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun nav(): Optional = nav.getOptional("nav") + /** + * Returns the raw JSON value of [stampDuty]. + * + * Unlike [stampDuty], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("stamp_duty") + @ExcludeMissing + fun _stampDuty(): JsonField = stampDuty - /** - * List of nominees - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun nominees(): Optional> = nominees.getOptional("nominees") + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - /** - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun transactions(): Optional> = - transactions.getOptional("transactions") + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - /** - * Type of mutual fund scheme - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun type(): Optional = type.getOptional("type") + fun toBuilder() = Builder().from(this) - /** - * Number of units held - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun units(): Optional = units.getOptional("units") + companion object { - /** - * Current market value of the holding - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun value(): Optional = value.getOptional("value") + /** + * Returns a mutable builder for constructing an instance of + * [AdditionalInfo]. + */ + @JvmStatic fun builder() = Builder() + } - /** - * Returns the raw JSON value of [additionalInfo]. - * - * Unlike [additionalInfo], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("additional_info") - @ExcludeMissing - fun _additionalInfo(): JsonField = additionalInfo + /** A builder for [AdditionalInfo]. */ + class Builder internal constructor() { + + private var capitalWithdrawal: JsonField = JsonMissing.of() + private var credit: JsonField = JsonMissing.of() + private var debit: JsonField = JsonMissing.of() + private var incomeDistribution: JsonField = JsonMissing.of() + private var orderNo: JsonField = JsonMissing.of() + private var price: JsonField = JsonMissing.of() + private var stampDuty: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(additionalInfo: AdditionalInfo) = apply { + capitalWithdrawal = additionalInfo.capitalWithdrawal + credit = additionalInfo.credit + debit = additionalInfo.debit + incomeDistribution = additionalInfo.incomeDistribution + orderNo = additionalInfo.orderNo + price = additionalInfo.price + stampDuty = additionalInfo.stampDuty + additionalProperties = + additionalInfo.additionalProperties.toMutableMap() + } - /** - * Returns the raw JSON value of [cost]. - * - * Unlike [cost], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("cost") @ExcludeMissing fun _cost(): JsonField = cost + /** Capital withdrawal amount (CDSL MF transactions) */ + fun capitalWithdrawal(capitalWithdrawal: Float) = + capitalWithdrawal(JsonField.of(capitalWithdrawal)) + + /** + * Sets [Builder.capitalWithdrawal] to an arbitrary JSON value. + * + * You should usually call [Builder.capitalWithdrawal] with a well-typed + * [Float] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun capitalWithdrawal(capitalWithdrawal: JsonField) = apply { + this.capitalWithdrawal = capitalWithdrawal + } - /** - * Returns the raw JSON value of [gain]. - * - * Unlike [gain], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("gain") @ExcludeMissing fun _gain(): JsonField = gain + /** Units credited (demat transactions) */ + fun credit(credit: Float) = credit(JsonField.of(credit)) + + /** + * Sets [Builder.credit] to an arbitrary JSON value. + * + * You should usually call [Builder.credit] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun credit(credit: JsonField) = apply { this.credit = credit } + + /** Units debited (demat transactions) */ + fun debit(debit: Float) = debit(JsonField.of(debit)) + + /** + * Sets [Builder.debit] to an arbitrary JSON value. + * + * You should usually call [Builder.debit] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun debit(debit: JsonField) = apply { this.debit = debit } + + /** Income distribution amount (CDSL MF transactions) */ + fun incomeDistribution(incomeDistribution: Float) = + incomeDistribution(JsonField.of(incomeDistribution)) + + /** + * Sets [Builder.incomeDistribution] to an arbitrary JSON value. + * + * You should usually call [Builder.incomeDistribution] with a well-typed + * [Float] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun incomeDistribution(incomeDistribution: JsonField) = apply { + this.incomeDistribution = incomeDistribution + } - /** - * Returns the raw JSON value of [isin]. - * - * Unlike [isin], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("isin") @ExcludeMissing fun _isin(): JsonField = isin + /** Order/transaction reference number (demat transactions) */ + fun orderNo(orderNo: String) = orderNo(JsonField.of(orderNo)) + + /** + * Sets [Builder.orderNo] to an arbitrary JSON value. + * + * You should usually call [Builder.orderNo] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun orderNo(orderNo: JsonField) = apply { this.orderNo = orderNo } + + /** Price per unit (NSDL/CDSL MF transactions) */ + fun price(price: Float) = price(JsonField.of(price)) + + /** + * Sets [Builder.price] to an arbitrary JSON value. + * + * You should usually call [Builder.price] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun price(price: JsonField) = apply { this.price = price } + + /** Stamp duty charged */ + fun stampDuty(stampDuty: Float) = stampDuty(JsonField.of(stampDuty)) + + /** + * Sets [Builder.stampDuty] to an arbitrary JSON value. + * + * You should usually call [Builder.stampDuty] with a well-typed [Float] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun stampDuty(stampDuty: JsonField) = apply { + this.stampDuty = stampDuty + } - /** - * Returns the raw JSON value of [name]. - * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - /** - * Returns the raw JSON value of [nav]. - * - * Unlike [nav], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("nav") @ExcludeMissing fun _nav(): JsonField = nav + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - /** - * Returns the raw JSON value of [nominees]. - * - * Unlike [nominees], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("nominees") - @ExcludeMissing - fun _nominees(): JsonField> = nominees + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } - /** - * Returns the raw JSON value of [transactions]. - * - * Unlike [transactions], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("transactions") - @ExcludeMissing - fun _transactions(): JsonField> = transactions + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - /** - * Returns the raw JSON value of [type]. - * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - /** - * Returns the raw JSON value of [units]. - * - * Unlike [units], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units + /** + * Returns an immutable instance of [AdditionalInfo]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AdditionalInfo = + AdditionalInfo( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties.toMutableMap(), + ) + } - /** - * Returns the raw JSON value of [value]. - * - * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value + private var validated: Boolean = false - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + capitalWithdrawal() + credit() + debit() + incomeDistribution() + orderNo() + price() + stampDuty() + validated = true + } - fun toBuilder() = Builder().from(this) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } - companion object { + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (capitalWithdrawal.asKnown().isPresent) 1 else 0) + + (if (credit.asKnown().isPresent) 1 else 0) + + (if (debit.asKnown().isPresent) 1 else 0) + + (if (incomeDistribution.asKnown().isPresent) 1 else 0) + + (if (orderNo.asKnown().isPresent) 1 else 0) + + (if (price.asKnown().isPresent) 1 else 0) + + (if (stampDuty.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - /** Returns a mutable builder for constructing an instance of [Scheme]. */ - @JvmStatic fun builder() = Builder() - } + return other is AdditionalInfo && + capitalWithdrawal == other.capitalWithdrawal && + credit == other.credit && + debit == other.debit && + incomeDistribution == other.incomeDistribution && + orderNo == other.orderNo && + price == other.price && + stampDuty == other.stampDuty && + additionalProperties == other.additionalProperties + } - /** A builder for [Scheme]. */ - class Builder internal constructor() { + private val hashCode: Int by lazy { + Objects.hash( + capitalWithdrawal, + credit, + debit, + incomeDistribution, + orderNo, + price, + stampDuty, + additionalProperties, + ) + } - private var additionalInfo: JsonField = JsonMissing.of() - private var cost: JsonField = JsonMissing.of() - private var gain: JsonField = JsonMissing.of() - private var isin: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var nav: JsonField = JsonMissing.of() - private var nominees: JsonField>? = null - private var transactions: JsonField>? = null - private var type: JsonField = JsonMissing.of() - private var units: JsonField = JsonMissing.of() - private var value: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + override fun hashCode(): Int = hashCode - @JvmSynthetic - internal fun from(scheme: Scheme) = apply { - additionalInfo = scheme.additionalInfo - cost = scheme.cost - gain = scheme.gain - isin = scheme.isin - name = scheme.name - nav = scheme.nav - nominees = scheme.nominees.map { it.toMutableList() } - transactions = scheme.transactions.map { it.toMutableList() } - type = scheme.type - units = scheme.units - value = scheme.value - additionalProperties = scheme.additionalProperties.toMutableMap() + override fun toString() = + "AdditionalInfo{capitalWithdrawal=$capitalWithdrawal, credit=$credit, debit=$debit, incomeDistribution=$incomeDistribution, orderNo=$orderNo, price=$price, stampDuty=$stampDuty, additionalProperties=$additionalProperties}" } - /** Additional information specific to the scheme */ - fun additionalInfo(additionalInfo: AdditionalInfo) = - additionalInfo(JsonField.of(additionalInfo)) - /** - * Sets [Builder.additionalInfo] to an arbitrary JSON value. - * - * You should usually call [Builder.additionalInfo] with a well-typed - * [AdditionalInfo] value instead. This method is primarily for setting the field to - * an undocumented or not yet supported value. + * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION, + * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT, + * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC, REVERSAL, + * UNKNOWN. */ - fun additionalInfo(additionalInfo: JsonField) = apply { - this.additionalInfo = additionalInfo - } + class Type @JsonCreator private constructor(private val value: JsonField) : + Enum { - /** Cost of investment */ - fun cost(cost: Float) = cost(JsonField.of(cost)) + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known 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. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value - /** - * Sets [Builder.cost] to an arbitrary JSON value. - * - * You should usually call [Builder.cost] with a well-typed [Float] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun cost(cost: JsonField) = apply { this.cost = cost } + companion object { - fun gain(gain: Gain) = gain(JsonField.of(gain)) + @JvmField val PURCHASE = of("PURCHASE") - /** - * Sets [Builder.gain] to an arbitrary JSON value. - * - * You should usually call [Builder.gain] with a well-typed [Gain] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun gain(gain: JsonField) = apply { this.gain = gain } + @JvmField val PURCHASE_SIP = of("PURCHASE_SIP") - /** ISIN code of the scheme */ - fun isin(isin: String) = isin(JsonField.of(isin)) + @JvmField val REDEMPTION = of("REDEMPTION") - /** - * Sets [Builder.isin] to an arbitrary JSON value. - * - * You should usually call [Builder.isin] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun isin(isin: JsonField) = apply { this.isin = isin } + @JvmField val SWITCH_IN = of("SWITCH_IN") - /** Scheme name */ - fun name(name: String) = name(JsonField.of(name)) + @JvmField val SWITCH_IN_MERGER = of("SWITCH_IN_MERGER") - /** - * Sets [Builder.name] to an arbitrary JSON value. - * - * You should usually call [Builder.name] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun name(name: JsonField) = apply { this.name = name } + @JvmField val SWITCH_OUT = of("SWITCH_OUT") + + @JvmField val SWITCH_OUT_MERGER = of("SWITCH_OUT_MERGER") + + @JvmField val DIVIDEND_PAYOUT = of("DIVIDEND_PAYOUT") + + @JvmField val DIVIDEND_REINVEST = of("DIVIDEND_REINVEST") + + @JvmField val SEGREGATION = of("SEGREGATION") + + @JvmField val STAMP_DUTY_TAX = of("STAMP_DUTY_TAX") + + @JvmField val TDS_TAX = of("TDS_TAX") - /** Net Asset Value per unit */ - fun nav(nav: Float) = nav(JsonField.of(nav)) + @JvmField val STT_TAX = of("STT_TAX") - /** - * Sets [Builder.nav] to an arbitrary JSON value. - * - * You should usually call [Builder.nav] with a well-typed [Float] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun nav(nav: JsonField) = apply { this.nav = nav } + @JvmField val MISC = of("MISC") - /** List of nominees */ - fun nominees(nominees: List) = nominees(JsonField.of(nominees)) + @JvmField val REVERSAL = of("REVERSAL") - /** - * Sets [Builder.nominees] to an arbitrary JSON value. - * - * You should usually call [Builder.nominees] with a well-typed `List` value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun nominees(nominees: JsonField>) = apply { - this.nominees = nominees.map { it.toMutableList() } - } + @JvmField val UNKNOWN = of("UNKNOWN") - /** - * Adds a single [String] to [nominees]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addNominee(nominee: String) = apply { - nominees = - (nominees ?: JsonField.of(mutableListOf())).also { - checkKnown("nominees", it).add(nominee) - } - } + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } - fun transactions(transactions: List) = - transactions(JsonField.of(transactions)) + /** An enum containing [Type]'s known values. */ + enum class Known { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + } - /** - * Sets [Builder.transactions] to an arbitrary JSON value. - * - * You should usually call [Builder.transactions] with a well-typed - * `List` value instead. This method is primarily for setting the field - * to an undocumented or not yet supported value. - */ - fun transactions(transactions: JsonField>) = apply { - this.transactions = transactions.map { it.toMutableList() } - } + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. 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. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + PURCHASE, + PURCHASE_SIP, + REDEMPTION, + SWITCH_IN, + SWITCH_IN_MERGER, + SWITCH_OUT, + SWITCH_OUT_MERGER, + DIVIDEND_PAYOUT, + DIVIDEND_REINVEST, + SEGREGATION, + STAMP_DUTY_TAX, + TDS_TAX, + STT_TAX, + MISC, + REVERSAL, + UNKNOWN, + /** + * An enum member indicating that [Type] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } - /** - * Adds a single [Transaction] to [transactions]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addTransaction(transaction: Transaction) = apply { - transactions = - (transactions ?: JsonField.of(mutableListOf())).also { - checkKnown("transactions", it).add(transaction) + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or + * if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + PURCHASE -> Value.PURCHASE + PURCHASE_SIP -> Value.PURCHASE_SIP + REDEMPTION -> Value.REDEMPTION + SWITCH_IN -> Value.SWITCH_IN + SWITCH_IN_MERGER -> Value.SWITCH_IN_MERGER + SWITCH_OUT -> Value.SWITCH_OUT + SWITCH_OUT_MERGER -> Value.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Value.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Value.DIVIDEND_REINVEST + SEGREGATION -> Value.SEGREGATION + STAMP_DUTY_TAX -> Value.STAMP_DUTY_TAX + TDS_TAX -> Value.TDS_TAX + STT_TAX -> Value.STT_TAX + MISC -> Value.MISC + REVERSAL -> Value.REVERSAL + UNKNOWN -> Value.UNKNOWN + else -> Value._UNKNOWN } - } - /** Type of mutual fund scheme */ - fun type(type: Type) = type(JsonField.of(type)) + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known + * and don't want to throw for the unknown case. + * + * @throws CasParserInvalidDataException if this class instance's value is a not + * a known member. + */ + fun known(): Known = + when (this) { + PURCHASE -> Known.PURCHASE + PURCHASE_SIP -> Known.PURCHASE_SIP + REDEMPTION -> Known.REDEMPTION + SWITCH_IN -> Known.SWITCH_IN + SWITCH_IN_MERGER -> Known.SWITCH_IN_MERGER + SWITCH_OUT -> Known.SWITCH_OUT + SWITCH_OUT_MERGER -> Known.SWITCH_OUT_MERGER + DIVIDEND_PAYOUT -> Known.DIVIDEND_PAYOUT + DIVIDEND_REINVEST -> Known.DIVIDEND_REINVEST + SEGREGATION -> Known.SEGREGATION + STAMP_DUTY_TAX -> Known.STAMP_DUTY_TAX + TDS_TAX -> Known.TDS_TAX + STT_TAX -> Known.STT_TAX + MISC -> Known.MISC + REVERSAL -> Known.REVERSAL + UNKNOWN -> Known.UNKNOWN + else -> throw CasParserInvalidDataException("Unknown Type: $value") + } - /** - * Sets [Builder.type] to an arbitrary JSON value. - * - * You should usually call [Builder.type] with a well-typed [Type] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun type(type: JsonField) = apply { this.type = type } + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws CasParserInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + CasParserInvalidDataException("Value is not a String") + } - /** Number of units held */ - fun units(units: Float) = units(JsonField.of(units)) + private var validated: Boolean = false - /** - * Sets [Builder.units] to an arbitrary JSON value. - * - * You should usually call [Builder.units] with a well-typed [Float] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun units(units: JsonField) = apply { this.units = units } + fun validate(): Type = apply { + if (validated) { + return@apply + } - /** Current market value of the holding */ - fun value(value: Float) = value(JsonField.of(value)) + known() + validated = true + } - /** - * Sets [Builder.value] to an arbitrary JSON value. - * - * You should usually call [Builder.value] with a well-typed [Float] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun value(value: JsonField) = apply { this.value = value } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) + return other is Type && value == other.value } - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Transaction && + additionalInfo == other.additionalInfo && + amount == other.amount && + balance == other.balance && + date == other.date && + description == other.description && + dividendRate == other.dividendRate && + nav == other.nav && + type == other.type && + units == other.units && + additionalProperties == other.additionalProperties } - /** - * Returns an immutable instance of [Scheme]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Scheme = - Scheme( + private val hashCode: Int by lazy { + Objects.hash( additionalInfo, - cost, - gain, - isin, - name, + amount, + balance, + date, + description, + dividendRate, nav, - (nominees ?: JsonMissing.of()).map { it.toImmutable() }, - (transactions ?: JsonMissing.of()).map { it.toImmutable() }, type, units, - value, - additionalProperties.toMutableMap(), + additionalProperties, ) - } - - private var validated: Boolean = false - - fun validate(): Scheme = apply { - if (validated) { - return@apply - } - - additionalInfo().ifPresent { it.validate() } - cost() - gain().ifPresent { it.validate() } - isin() - name() - nav() - nominees() - transactions().ifPresent { it.forEach { it.validate() } } - type().ifPresent { it.validate() } - units() - value() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false } - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + - (if (cost.asKnown().isPresent) 1 else 0) + - (gain.asKnown().getOrNull()?.validity() ?: 0) + - (if (isin.asKnown().isPresent) 1 else 0) + - (if (name.asKnown().isPresent) 1 else 0) + - (if (nav.asKnown().isPresent) 1 else 0) + - (nominees.asKnown().getOrNull()?.size ?: 0) + - (transactions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + - (type.asKnown().getOrNull()?.validity() ?: 0) + - (if (units.asKnown().isPresent) 1 else 0) + - (if (value.asKnown().isPresent) 1 else 0) - - /** Additional information specific to the scheme */ - class AdditionalInfo - private constructor( - private val advisor: JsonField, - private val amfi: JsonField, - private val closeUnits: JsonField, - private val openUnits: JsonField, - private val rtaCode: JsonField, - private val additionalProperties: MutableMap, - ) { + override fun hashCode(): Int = hashCode - @JsonCreator - private constructor( - @JsonProperty("advisor") - @ExcludeMissing - advisor: JsonField = JsonMissing.of(), - @JsonProperty("amfi") - @ExcludeMissing - amfi: JsonField = JsonMissing.of(), - @JsonProperty("close_units") - @ExcludeMissing - closeUnits: JsonField = JsonMissing.of(), - @JsonProperty("open_units") - @ExcludeMissing - openUnits: JsonField = JsonMissing.of(), - @JsonProperty("rta_code") - @ExcludeMissing - rtaCode: JsonField = JsonMissing.of(), - ) : this(advisor, amfi, closeUnits, openUnits, rtaCode, mutableMapOf()) + override fun toString() = + "Transaction{additionalInfo=$additionalInfo, amount=$amount, balance=$balance, date=$date, description=$description, dividendRate=$dividendRate, nav=$nav, type=$type, units=$units, additionalProperties=$additionalProperties}" + } - /** - * Financial advisor name (CAMS/KFintech) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun advisor(): Optional = advisor.getOptional("advisor") + /** Type of mutual fund scheme */ + class Type @JsonCreator private constructor(private val value: JsonField) : + Enum { /** - * AMFI code for the scheme (CAMS/KFintech) + * Returns this class instance's raw value. * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known 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. */ - fun amfi(): Optional = amfi.getOptional("amfi") + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - /** - * Closing balance units (CAMS/KFintech) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun closeUnits(): Optional = closeUnits.getOptional("close_units") + companion object { - /** - * Opening balance units (CAMS/KFintech) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun openUnits(): Optional = openUnits.getOptional("open_units") + @JvmField val EQUITY = of("Equity") - /** - * RTA code for the scheme (CAMS/KFintech) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun rtaCode(): Optional = rtaCode.getOptional("rta_code") + @JvmField val DEBT = of("Debt") + + @JvmField val HYBRID = of("Hybrid") + + @JvmField val OTHER = of("Other") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + EQUITY, + DEBT, + HYBRID, + OTHER, + } /** - * Returns the raw JSON value of [advisor]. + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. * - * Unlike [advisor], this method doesn't throw if the JSON field has an unexpected - * type. + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. 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. + * - It was constructed with an arbitrary value using the [of] method. */ - @JsonProperty("advisor") @ExcludeMissing fun _advisor(): JsonField = advisor + enum class Value { + EQUITY, + DEBT, + HYBRID, + OTHER, + /** + * An enum member indicating that [Type] was instantiated with an unknown value. + */ + _UNKNOWN, + } /** - * Returns the raw JSON value of [amfi]. + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. * - * Unlike [amfi], this method doesn't throw if the JSON field has an unexpected - * type. + * Use the [known] method instead if you're certain the value is always known or if + * you want to throw for the unknown case. */ - @JsonProperty("amfi") @ExcludeMissing fun _amfi(): JsonField = amfi + fun value(): Value = + when (this) { + EQUITY -> Value.EQUITY + DEBT -> Value.DEBT + HYBRID -> Value.HYBRID + OTHER -> Value.OTHER + else -> Value._UNKNOWN + } /** - * Returns the raw JSON value of [closeUnits]. + * Returns an enum member corresponding to this class instance's value. * - * Unlike [closeUnits], this method doesn't throw if the JSON field has an - * unexpected type. + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws CasParserInvalidDataException if this class instance's value is a not a + * known member. */ - @JsonProperty("close_units") - @ExcludeMissing - fun _closeUnits(): JsonField = closeUnits + fun known(): Known = + when (this) { + EQUITY -> Known.EQUITY + DEBT -> Known.DEBT + HYBRID -> Known.HYBRID + OTHER -> Known.OTHER + else -> throw CasParserInvalidDataException("Unknown Type: $value") + } /** - * Returns the raw JSON value of [openUnits]. + * Returns this class instance's primitive wire representation. * - * Unlike [openUnits], this method doesn't throw if the JSON field has an unexpected - * type. + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws CasParserInvalidDataException if this class instance's value does not + * have the expected primitive type. */ - @JsonProperty("open_units") - @ExcludeMissing - fun _openUnits(): JsonField = openUnits + fun asString(): String = + _value().asString().orElseThrow { + CasParserInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } /** - * Returns the raw JSON value of [rtaCode]. + * Returns a score indicating how many valid values are contained in this object + * recursively. * - * Unlike [rtaCode], this method doesn't throw if the JSON field has an unexpected - * type. + * Used for best match union deserialization. */ - @JsonProperty("rta_code") - @ExcludeMissing - fun _rtaCode(): JsonField = rtaCode + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Scheme && + additionalInfo == other.additionalInfo && + cost == other.cost && + gain == other.gain && + isin == other.isin && + name == other.name && + nav == other.nav && + nominees == other.nominees && + transactions == other.transactions && + type == other.type && + units == other.units && + value == other.value && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + cost, + gain, + isin, + name, + nav, + nominees, + transactions, + type, + units, + value, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Scheme{additionalInfo=$additionalInfo, cost=$cost, gain=$gain, isin=$isin, name=$name, nav=$nav, nominees=$nominees, transactions=$transactions, type=$type, units=$units, value=$value, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is MutualFund && + additionalInfo == other.additionalInfo && + amc == other.amc && + folioNumber == other.folioNumber && + linkedHolders == other.linkedHolders && + registrar == other.registrar && + schemes == other.schemes && + value == other.value && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + additionalInfo, + amc, + folioNumber, + linkedHolders, + registrar, + schemes, + value, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "MutualFund{additionalInfo=$additionalInfo, amc=$amc, folioNumber=$folioNumber, linkedHolders=$linkedHolders, registrar=$registrar, schemes=$schemes, value=$value, additionalProperties=$additionalProperties}" + } + + class Np + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonValue, + private val cra: JsonField, + private val funds: JsonField>, + private val linkedHolders: JsonField>, + private val pran: JsonField, + private val value: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") + @ExcludeMissing + additionalInfo: JsonValue = JsonMissing.of(), + @JsonProperty("cra") @ExcludeMissing cra: JsonField = JsonMissing.of(), + @JsonProperty("funds") @ExcludeMissing funds: JsonField> = JsonMissing.of(), + @JsonProperty("linked_holders") + @ExcludeMissing + linkedHolders: JsonField> = JsonMissing.of(), + @JsonProperty("pran") @ExcludeMissing pran: JsonField = JsonMissing.of(), + @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), + ) : this(additionalInfo, cra, funds, linkedHolders, pran, value, mutableMapOf()) + + /** Additional information specific to the NPS account */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonValue = additionalInfo + + /** + * Central Record Keeping Agency name + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun cra(): Optional = cra.getOptional("cra") - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + /** + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun funds(): Optional> = funds.getOptional("funds") - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + /** + * List of account holders linked to this NPS account + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun linkedHolders(): Optional> = + linkedHolders.getOptional("linked_holders") - fun toBuilder() = Builder().from(this) + /** + * Permanent Retirement Account Number (PRAN) + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun pran(): Optional = pran.getOptional("pran") - companion object { + /** + * Total value of the NPS account + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun value(): Optional = value.getOptional("value") - /** - * Returns a mutable builder for constructing an instance of [AdditionalInfo]. - */ - @JvmStatic fun builder() = Builder() - } + /** + * Returns the raw JSON value of [cra]. + * + * Unlike [cra], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cra") @ExcludeMissing fun _cra(): JsonField = cra - /** A builder for [AdditionalInfo]. */ - class Builder internal constructor() { + /** + * Returns the raw JSON value of [funds]. + * + * Unlike [funds], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("funds") @ExcludeMissing fun _funds(): JsonField> = funds - private var advisor: JsonField = JsonMissing.of() - private var amfi: JsonField = JsonMissing.of() - private var closeUnits: JsonField = JsonMissing.of() - private var openUnits: JsonField = JsonMissing.of() - private var rtaCode: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + /** + * Returns the raw JSON value of [linkedHolders]. + * + * Unlike [linkedHolders], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("linked_holders") + @ExcludeMissing + fun _linkedHolders(): JsonField> = linkedHolders - @JvmSynthetic - internal fun from(additionalInfo: AdditionalInfo) = apply { - advisor = additionalInfo.advisor - amfi = additionalInfo.amfi - closeUnits = additionalInfo.closeUnits - openUnits = additionalInfo.openUnits - rtaCode = additionalInfo.rtaCode - additionalProperties = additionalInfo.additionalProperties.toMutableMap() - } + /** + * Returns the raw JSON value of [pran]. + * + * Unlike [pran], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pran") @ExcludeMissing fun _pran(): JsonField = pran - /** Financial advisor name (CAMS/KFintech) */ - fun advisor(advisor: String) = advisor(JsonField.of(advisor)) + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value - /** - * Sets [Builder.advisor] to an arbitrary JSON value. - * - * You should usually call [Builder.advisor] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun advisor(advisor: JsonField) = apply { this.advisor = advisor } + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - /** AMFI code for the scheme (CAMS/KFintech) */ - fun amfi(amfi: String) = amfi(JsonField.of(amfi)) + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - /** - * Sets [Builder.amfi] to an arbitrary JSON value. - * - * You should usually call [Builder.amfi] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun amfi(amfi: JsonField) = apply { this.amfi = amfi } + fun toBuilder() = Builder().from(this) - /** Closing balance units (CAMS/KFintech) */ - fun closeUnits(closeUnits: Float) = closeUnits(JsonField.of(closeUnits)) + companion object { - /** - * Sets [Builder.closeUnits] to an arbitrary JSON value. - * - * You should usually call [Builder.closeUnits] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun closeUnits(closeUnits: JsonField) = apply { - this.closeUnits = closeUnits - } + /** Returns a mutable builder for constructing an instance of [Np]. */ + @JvmStatic fun builder() = Builder() + } - /** Opening balance units (CAMS/KFintech) */ - fun openUnits(openUnits: Float) = openUnits(JsonField.of(openUnits)) + /** A builder for [Np]. */ + class Builder internal constructor() { - /** - * Sets [Builder.openUnits] to an arbitrary JSON value. - * - * You should usually call [Builder.openUnits] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun openUnits(openUnits: JsonField) = apply { - this.openUnits = openUnits - } + private var additionalInfo: JsonValue = JsonMissing.of() + private var cra: JsonField = JsonMissing.of() + private var funds: JsonField>? = null + private var linkedHolders: JsonField>? = null + private var pran: JsonField = JsonMissing.of() + private var value: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** RTA code for the scheme (CAMS/KFintech) */ - fun rtaCode(rtaCode: String) = rtaCode(JsonField.of(rtaCode)) + @JvmSynthetic + internal fun from(np: Np) = apply { + additionalInfo = np.additionalInfo + cra = np.cra + funds = np.funds.map { it.toMutableList() } + linkedHolders = np.linkedHolders.map { it.toMutableList() } + pran = np.pran + value = np.value + additionalProperties = np.additionalProperties.toMutableMap() + } - /** - * Sets [Builder.rtaCode] to an arbitrary JSON value. - * - * You should usually call [Builder.rtaCode] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun rtaCode(rtaCode: JsonField) = apply { this.rtaCode = rtaCode } + /** Additional information specific to the NPS account */ + fun additionalInfo(additionalInfo: JsonValue) = apply { + this.additionalInfo = additionalInfo + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** Central Record Keeping Agency name */ + fun cra(cra: String) = cra(JsonField.of(cra)) - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + /** + * Sets [Builder.cra] to an arbitrary JSON value. + * + * You should usually call [Builder.cra] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun cra(cra: JsonField) = apply { this.cra = cra } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + fun funds(funds: List) = funds(JsonField.of(funds)) - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } + /** + * Sets [Builder.funds] to an arbitrary JSON value. + * + * You should usually call [Builder.funds] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun funds(funds: JsonField>) = apply { + this.funds = funds.map { it.toMutableList() } + } - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) + /** + * Adds a single [Fund] to [funds]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addFund(fund: Fund) = apply { + funds = + (funds ?: JsonField.of(mutableListOf())).also { + checkKnown("funds", it).add(fund) } + } - /** - * Returns an immutable instance of [AdditionalInfo]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): AdditionalInfo = - AdditionalInfo( - advisor, - amfi, - closeUnits, - openUnits, - rtaCode, - additionalProperties.toMutableMap(), - ) - } + /** List of account holders linked to this NPS account */ + fun linkedHolders(linkedHolders: List) = + linkedHolders(JsonField.of(linkedHolders)) - private var validated: Boolean = false + /** + * Sets [Builder.linkedHolders] to an arbitrary JSON value. + * + * You should usually call [Builder.linkedHolders] with a well-typed + * `List` value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun linkedHolders(linkedHolders: JsonField>) = apply { + this.linkedHolders = linkedHolders.map { it.toMutableList() } + } - fun validate(): AdditionalInfo = apply { - if (validated) { - return@apply + /** + * Adds a single [LinkedHolder] to [linkedHolders]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addLinkedHolder(linkedHolder: LinkedHolder) = apply { + linkedHolders = + (linkedHolders ?: JsonField.of(mutableListOf())).also { + checkKnown("linkedHolders", it).add(linkedHolder) } + } - advisor() - amfi() - closeUnits() - openUnits() - rtaCode() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + /** Permanent Retirement Account Number (PRAN) */ + fun pran(pran: String) = pran(JsonField.of(pran)) - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (advisor.asKnown().isPresent) 1 else 0) + - (if (amfi.asKnown().isPresent) 1 else 0) + - (if (closeUnits.asKnown().isPresent) 1 else 0) + - (if (openUnits.asKnown().isPresent) 1 else 0) + - (if (rtaCode.asKnown().isPresent) 1 else 0) + /** + * Sets [Builder.pran] to an arbitrary JSON value. + * + * You should usually call [Builder.pran] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun pran(pran: JsonField) = apply { this.pran = pran } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** Total value of the NPS account */ + fun value(value: Float) = value(JsonField.of(value)) - return other is AdditionalInfo && - advisor == other.advisor && - amfi == other.amfi && - closeUnits == other.closeUnits && - openUnits == other.openUnits && - rtaCode == other.rtaCode && - additionalProperties == other.additionalProperties - } + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [Float] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun value(value: JsonField) = apply { this.value = value } - private val hashCode: Int by lazy { - Objects.hash( - advisor, - amfi, - closeUnits, - openUnits, - rtaCode, - additionalProperties, - ) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - override fun hashCode(): Int = hashCode + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - override fun toString() = - "AdditionalInfo{advisor=$advisor, amfi=$amfi, closeUnits=$closeUnits, openUnits=$openUnits, rtaCode=$rtaCode, additionalProperties=$additionalProperties}" + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) } - class Gain - private constructor( - private val absolute: JsonField, - private val percentage: JsonField, - private val additionalProperties: MutableMap, - ) { + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - @JsonCreator - private constructor( - @JsonProperty("absolute") - @ExcludeMissing - absolute: JsonField = JsonMissing.of(), - @JsonProperty("percentage") - @ExcludeMissing - percentage: JsonField = JsonMissing.of(), - ) : this(absolute, percentage, mutableMapOf()) + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - /** - * Absolute gain or loss - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun absolute(): Optional = absolute.getOptional("absolute") + /** + * Returns an immutable instance of [Np]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Np = + Np( + additionalInfo, + cra, + (funds ?: JsonMissing.of()).map { it.toImmutable() }, + (linkedHolders ?: JsonMissing.of()).map { it.toImmutable() }, + pran, + value, + additionalProperties.toMutableMap(), + ) + } - /** - * Percentage gain or loss - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun percentage(): Optional = percentage.getOptional("percentage") + private var validated: Boolean = false - /** - * Returns the raw JSON value of [absolute]. - * - * Unlike [absolute], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("absolute") - @ExcludeMissing - fun _absolute(): JsonField = absolute + fun validate(): Np = apply { + if (validated) { + return@apply + } - /** - * Returns the raw JSON value of [percentage]. - * - * Unlike [percentage], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("percentage") - @ExcludeMissing - fun _percentage(): JsonField = percentage + cra() + funds().ifPresent { it.forEach { it.validate() } } + linkedHolders().ifPresent { it.forEach { it.validate() } } + pran() + value() + validated = true + } - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } - @JsonAnyGetter + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (cra.asKnown().isPresent) 1 else 0) + + (funds.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (linkedHolders.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (pran.asKnown().isPresent) 1 else 0) + + (if (value.asKnown().isPresent) 1 else 0) + + class Fund + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val additionalInfo: JsonField, + private val cost: JsonField, + private val name: JsonField, + private val nav: JsonField, + private val units: JsonField, + private val value: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("additional_info") @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + additionalInfo: JsonField = JsonMissing.of(), + @JsonProperty("cost") @ExcludeMissing cost: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("nav") @ExcludeMissing nav: JsonField = JsonMissing.of(), + @JsonProperty("units") @ExcludeMissing units: JsonField = JsonMissing.of(), + @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), + ) : this(additionalInfo, cost, name, nav, units, value, mutableMapOf()) - fun toBuilder() = Builder().from(this) + /** + * Additional information specific to the NPS fund + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun additionalInfo(): Optional = + additionalInfo.getOptional("additional_info") - companion object { + /** + * Cost of investment + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun cost(): Optional = cost.getOptional("cost") - /** Returns a mutable builder for constructing an instance of [Gain]. */ - @JvmStatic fun builder() = Builder() - } + /** + * Name of the NPS fund + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") - /** A builder for [Gain]. */ - class Builder internal constructor() { + /** + * Net Asset Value per unit + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun nav(): Optional = nav.getOptional("nav") - private var absolute: JsonField = JsonMissing.of() - private var percentage: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + /** + * Number of units held + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun units(): Optional = units.getOptional("units") - @JvmSynthetic - internal fun from(gain: Gain) = apply { - absolute = gain.absolute - percentage = gain.percentage - additionalProperties = gain.additionalProperties.toMutableMap() - } + /** + * Current market value of the holding + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun value(): Optional = value.getOptional("value") - /** Absolute gain or loss */ - fun absolute(absolute: Float) = absolute(JsonField.of(absolute)) + /** + * Returns the raw JSON value of [additionalInfo]. + * + * Unlike [additionalInfo], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("additional_info") + @ExcludeMissing + fun _additionalInfo(): JsonField = additionalInfo - /** - * Sets [Builder.absolute] to an arbitrary JSON value. - * - * You should usually call [Builder.absolute] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun absolute(absolute: JsonField) = apply { this.absolute = absolute } + /** + * Returns the raw JSON value of [cost]. + * + * Unlike [cost], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cost") @ExcludeMissing fun _cost(): JsonField = cost - /** Percentage gain or loss */ - fun percentage(percentage: Float) = percentage(JsonField.of(percentage)) + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** - * Sets [Builder.percentage] to an arbitrary JSON value. - * - * You should usually call [Builder.percentage] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun percentage(percentage: JsonField) = apply { - this.percentage = percentage - } + /** + * Returns the raw JSON value of [nav]. + * + * Unlike [nav], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("nav") @ExcludeMissing fun _nav(): JsonField = nav - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** + * Returns the raw JSON value of [units]. + * + * Unlike [units], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + fun toBuilder() = Builder().from(this) - /** - * Returns an immutable instance of [Gain]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Gain = - Gain(absolute, percentage, additionalProperties.toMutableMap()) - } + companion object { - private var validated: Boolean = false + /** Returns a mutable builder for constructing an instance of [Fund]. */ + @JvmStatic fun builder() = Builder() + } - fun validate(): Gain = apply { - if (validated) { - return@apply - } + /** A builder for [Fund]. */ + class Builder internal constructor() { - absolute() - percentage() - validated = true + private var additionalInfo: JsonField = JsonMissing.of() + private var cost: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var nav: JsonField = JsonMissing.of() + private var units: JsonField = JsonMissing.of() + private var value: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(fund: Fund) = apply { + additionalInfo = fund.additionalInfo + cost = fund.cost + name = fund.name + nav = fund.nav + units = fund.units + value = fund.value + additionalProperties = fund.additionalProperties.toMutableMap() } - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + /** Additional information specific to the NPS fund */ + fun additionalInfo(additionalInfo: AdditionalInfo) = + additionalInfo(JsonField.of(additionalInfo)) /** - * Returns a score indicating how many valid values are contained in this object - * recursively. + * Sets [Builder.additionalInfo] to an arbitrary JSON value. * - * Used for best match union deserialization. + * You should usually call [Builder.additionalInfo] with a well-typed + * [AdditionalInfo] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. */ - @JvmSynthetic - internal fun validity(): Int = - (if (absolute.asKnown().isPresent) 1 else 0) + - (if (percentage.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Gain && - absolute == other.absolute && - percentage == other.percentage && - additionalProperties == other.additionalProperties + fun additionalInfo(additionalInfo: JsonField) = apply { + this.additionalInfo = additionalInfo } - private val hashCode: Int by lazy { - Objects.hash(absolute, percentage, additionalProperties) - } + /** Cost of investment */ + fun cost(cost: Float) = cost(JsonField.of(cost)) - override fun hashCode(): Int = hashCode + /** + * Sets [Builder.cost] to an arbitrary JSON value. + * + * You should usually call [Builder.cost] with a well-typed [Float] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun cost(cost: JsonField) = apply { this.cost = cost } - override fun toString() = - "Gain{absolute=$absolute, percentage=$percentage, additionalProperties=$additionalProperties}" - } + /** Name of the NPS fund */ + fun name(name: String) = name(JsonField.of(name)) - class Transaction - private constructor( - private val amount: JsonField, - private val balance: JsonField, - private val date: JsonField, - private val description: JsonField, - private val dividendRate: JsonField, - private val nav: JsonField, - private val type: JsonField, - private val units: JsonField, - private val additionalProperties: MutableMap, - ) { + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } - @JsonCreator - private constructor( - @JsonProperty("amount") - @ExcludeMissing - amount: JsonField = JsonMissing.of(), - @JsonProperty("balance") - @ExcludeMissing - balance: JsonField = JsonMissing.of(), - @JsonProperty("date") - @ExcludeMissing - date: JsonField = JsonMissing.of(), - @JsonProperty("description") - @ExcludeMissing - description: JsonField = JsonMissing.of(), - @JsonProperty("dividend_rate") - @ExcludeMissing - dividendRate: JsonField = JsonMissing.of(), - @JsonProperty("nav") @ExcludeMissing nav: JsonField = JsonMissing.of(), - @JsonProperty("type") - @ExcludeMissing - type: JsonField = JsonMissing.of(), - @JsonProperty("units") - @ExcludeMissing - units: JsonField = JsonMissing.of(), - ) : this( - amount, - balance, - date, - description, - dividendRate, - nav, - type, - units, - mutableMapOf(), - ) + /** Net Asset Value per unit */ + fun nav(nav: Float) = nav(JsonField.of(nav)) /** - * Transaction amount + * Sets [Builder.nav] to an arbitrary JSON value. * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * You should usually call [Builder.nav] with a well-typed [Float] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun amount(): Optional = amount.getOptional("amount") + fun nav(nav: JsonField) = apply { this.nav = nav } + + /** Number of units held */ + fun units(units: Float) = units(JsonField.of(units)) /** - * Balance units after transaction + * Sets [Builder.units] to an arbitrary JSON value. * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * You should usually call [Builder.units] with a well-typed [Float] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun balance(): Optional = balance.getOptional("balance") + fun units(units: JsonField) = apply { this.units = units } + + /** Current market value of the holding */ + fun value(value: Float) = value(JsonField.of(value)) /** - * Transaction date + * Sets [Builder.value] to an arbitrary JSON value. * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * You should usually call [Builder.value] with a well-typed [Float] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun date(): Optional = date.getOptional("date") + fun value(value: JsonField) = apply { this.value = value } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } /** - * Transaction description + * Returns an immutable instance of [Fund]. * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * Further updates to this [Builder] will not mutate the returned instance. */ - fun description(): Optional = description.getOptional("description") + fun build(): Fund = + Fund( + additionalInfo, + cost, + name, + nav, + units, + value, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Fund = apply { + if (validated) { + return@apply + } + + additionalInfo().ifPresent { it.validate() } + cost() + name() + nav() + units() + value() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) + + (if (cost.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (nav.asKnown().isPresent) 1 else 0) + + (if (units.asKnown().isPresent) 1 else 0) + + (if (value.asKnown().isPresent) 1 else 0) - /** - * Dividend rate (for dividend transactions) - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun dividendRate(): Optional = dividendRate.getOptional("dividend_rate") + /** Additional information specific to the NPS fund */ + class AdditionalInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val manager: JsonField, + private val tier: JsonField, + private val additionalProperties: MutableMap, + ) { - /** - * NAV on transaction date - * - * @throws CasParserInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun nav(): Optional = nav.getOptional("nav") + @JsonCreator + private constructor( + @JsonProperty("manager") + @ExcludeMissing + manager: JsonField = JsonMissing.of(), + @JsonProperty("tier") @ExcludeMissing tier: JsonField = JsonMissing.of(), + ) : this(manager, tier, mutableMapOf()) /** - * Transaction type detected based on description. Possible values are - * PURCHASE,PURCHASE_SIP,REDEMPTION,SWITCH_IN,SWITCH_IN_MERGER,SWITCH_OUT,SWITCH_OUT_MERGER,DIVIDEND_PAYOUT,DIVIDEND_REINVESTMENT,SEGREGATION,STAMP_DUTY_TAX,TDS_TAX,STT_TAX,MISC. - * If dividend_rate is present, then possible values are dividend_rate is applicable - * only for DIVIDEND_PAYOUT and DIVIDEND_REINVESTMENT. + * Fund manager name * * @throws CasParserInvalidDataException if the JSON field has an unexpected type * (e.g. if the server responded with an unexpected value). */ - fun type(): Optional = type.getOptional("type") + fun manager(): Optional = manager.getOptional("manager") /** - * Number of units involved + * NPS tier (Tier I or Tier II) * * @throws CasParserInvalidDataException if the JSON field has an unexpected type * (e.g. if the server responded with an unexpected value). */ - fun units(): Optional = units.getOptional("units") - - /** - * Returns the raw JSON value of [amount]. - * - * Unlike [amount], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("amount") @ExcludeMissing fun _amount(): JsonField = amount - - /** - * Returns the raw JSON value of [balance]. - * - * Unlike [balance], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("balance") @ExcludeMissing fun _balance(): JsonField = balance - - /** - * Returns the raw JSON value of [date]. - * - * Unlike [date], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("date") @ExcludeMissing fun _date(): JsonField = date - - /** - * Returns the raw JSON value of [description]. - * - * Unlike [description], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("description") - @ExcludeMissing - fun _description(): JsonField = description - - /** - * Returns the raw JSON value of [dividendRate]. - * - * Unlike [dividendRate], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("dividend_rate") - @ExcludeMissing - fun _dividendRate(): JsonField = dividendRate - - /** - * Returns the raw JSON value of [nav]. - * - * Unlike [nav], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("nav") @ExcludeMissing fun _nav(): JsonField = nav + fun tier(): Optional = tier.getOptional("tier") /** - * Returns the raw JSON value of [type]. + * Returns the raw JSON value of [manager]. * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected + * Unlike [manager], this method doesn't throw if the JSON field has an unexpected * type. */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + @JsonProperty("manager") @ExcludeMissing fun _manager(): JsonField = manager /** - * Returns the raw JSON value of [units]. + * Returns the raw JSON value of [tier]. * - * Unlike [units], this method doesn't throw if the JSON field has an unexpected + * Unlike [tier], this method doesn't throw if the JSON field has an unexpected * type. */ - @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units + @JsonProperty("tier") @ExcludeMissing fun _tier(): JsonField = tier @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -6517,446 +16621,469 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [Transaction]. */ + /** + * Returns a mutable builder for constructing an instance of [AdditionalInfo]. + */ @JvmStatic fun builder() = Builder() } - /** A builder for [Transaction]. */ + /** A builder for [AdditionalInfo]. */ class Builder internal constructor() { - private var amount: JsonField = JsonMissing.of() - private var balance: JsonField = JsonMissing.of() - private var date: JsonField = JsonMissing.of() - private var description: JsonField = JsonMissing.of() - private var dividendRate: JsonField = JsonMissing.of() - private var nav: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() - private var units: JsonField = JsonMissing.of() + private var manager: JsonField = JsonMissing.of() + private var tier: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(transaction: Transaction) = apply { - amount = transaction.amount - balance = transaction.balance - date = transaction.date - description = transaction.description - dividendRate = transaction.dividendRate - nav = transaction.nav - type = transaction.type - units = transaction.units - additionalProperties = transaction.additionalProperties.toMutableMap() + internal fun from(additionalInfo: AdditionalInfo) = apply { + manager = additionalInfo.manager + tier = additionalInfo.tier + additionalProperties = additionalInfo.additionalProperties.toMutableMap() } - /** Transaction amount */ - fun amount(amount: Float) = amount(JsonField.of(amount)) + /** Fund manager name */ + fun manager(manager: String) = manager(JsonField.of(manager)) /** - * Sets [Builder.amount] to an arbitrary JSON value. + * Sets [Builder.manager] to an arbitrary JSON value. * - * You should usually call [Builder.amount] with a well-typed [Float] value + * You should usually call [Builder.manager] with a well-typed [String] value * instead. This method is primarily for setting the field to an undocumented or * not yet supported value. */ - fun amount(amount: JsonField) = apply { this.amount = amount } + fun manager(manager: JsonField) = apply { this.manager = manager } - /** Balance units after transaction */ - fun balance(balance: Float) = balance(JsonField.of(balance)) + /** NPS tier (Tier I or Tier II) */ + fun tier(tier: Tier?) = tier(JsonField.ofNullable(tier)) + + /** Alias for calling [Builder.tier] with `tier.orElse(null)`. */ + fun tier(tier: Optional) = tier(tier.getOrNull()) /** - * Sets [Builder.balance] to an arbitrary JSON value. + * Sets [Builder.tier] to an arbitrary JSON value. * - * You should usually call [Builder.balance] with a well-typed [Float] value + * You should usually call [Builder.tier] with a well-typed [Tier] value * instead. This method is primarily for setting the field to an undocumented or * not yet supported value. */ - fun balance(balance: JsonField) = apply { this.balance = balance } + fun tier(tier: JsonField) = apply { this.tier = tier } - /** Transaction date */ - fun date(date: LocalDate) = date(JsonField.of(date)) + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - /** - * Sets [Builder.date] to an arbitrary JSON value. - * - * You should usually call [Builder.date] with a well-typed [LocalDate] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun date(date: JsonField) = apply { this.date = date } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - /** Transaction description */ - fun description(description: String) = description(JsonField.of(description)) + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } /** - * Sets [Builder.description] to an arbitrary JSON value. + * Returns an immutable instance of [AdditionalInfo]. * - * You should usually call [Builder.description] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. + * Further updates to this [Builder] will not mutate the returned instance. */ - fun description(description: JsonField) = apply { - this.description = description + fun build(): AdditionalInfo = + AdditionalInfo(manager, tier, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): AdditionalInfo = apply { + if (validated) { + return@apply + } + + manager() + tier().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false } - /** Dividend rate (for dividend transactions) */ - fun dividendRate(dividendRate: Float) = dividendRate(JsonField.of(dividendRate)) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (manager.asKnown().isPresent) 1 else 0) + + (tier.asKnown().getOrNull()?.validity() ?: 0) + + /** NPS tier (Tier I or Tier II) */ + class Tier @JsonCreator private constructor(private val value: JsonField) : + Enum { /** - * Sets [Builder.dividendRate] to an arbitrary JSON value. + * Returns this class instance's raw value. * - * You should usually call [Builder.dividendRate] with a well-typed [Float] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known 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. */ - fun dividendRate(dividendRate: JsonField) = apply { - this.dividendRate = dividendRate + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value + + companion object { + + @JvmField val _1 = of(1.0) + + @JvmField val _2 = of(2.0) + + @JvmStatic fun of(value: Double) = Tier(JsonField.of(value)) } - /** NAV on transaction date */ - fun nav(nav: Float) = nav(JsonField.of(nav)) + /** An enum containing [Tier]'s known values. */ + enum class Known { + _1, + _2, + } /** - * Sets [Builder.nav] to an arbitrary JSON value. + * An enum containing [Tier]'s known values, as well as an [_UNKNOWN] member. * - * You should usually call [Builder.nav] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. + * An instance of [Tier] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. 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. + * - It was constructed with an arbitrary value using the [of] method. */ - fun nav(nav: JsonField) = apply { this.nav = nav } + enum class Value { + _1, + _2, + /** + * An enum member indicating that [Tier] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } /** - * Transaction type detected based on description. Possible values are - * PURCHASE,PURCHASE_SIP,REDEMPTION,SWITCH_IN,SWITCH_IN_MERGER,SWITCH_OUT,SWITCH_OUT_MERGER,DIVIDEND_PAYOUT,DIVIDEND_REINVESTMENT,SEGREGATION,STAMP_DUTY_TAX,TDS_TAX,STT_TAX,MISC. - * If dividend_rate is present, then possible values are dividend_rate is - * applicable only for DIVIDEND_PAYOUT and DIVIDEND_REINVESTMENT. + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or + * if you want to throw for the unknown case. */ - fun type(type: String) = type(JsonField.of(type)) + fun value(): Value = + when (this) { + _1 -> Value._1 + _2 -> Value._2 + else -> Value._UNKNOWN + } /** - * Sets [Builder.type] to an arbitrary JSON value. + * Returns an enum member corresponding to this class instance's value. * - * You should usually call [Builder.type] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. + * Use the [value] method instead if you're uncertain the value is always known + * and don't want to throw for the unknown case. + * + * @throws CasParserInvalidDataException if this class instance's value is a not + * a known member. */ - fun type(type: JsonField) = apply { this.type = type } - - /** Number of units involved */ - fun units(units: Float) = units(JsonField.of(units)) + fun known(): Known = + when (this) { + _1 -> Known._1 + _2 -> Known._2 + else -> throw CasParserInvalidDataException("Unknown Tier: $value") + } /** - * Sets [Builder.units] to an arbitrary JSON value. + * Returns this class instance's primitive wire representation. * - * You should usually call [Builder.units] with a well-typed [Float] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. + * @throws CasParserInvalidDataException if this class instance's value does not + * have the expected primitive type. */ - fun units(units: JsonField) = apply { this.units = units } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + fun asDouble(): Double = + _value().asNumber().getOrNull()?.toDouble() + ?: throw CasParserInvalidDataException("Value is not a Double") - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + private var validated: Boolean = false - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) + fun validate(): Tier = apply { + if (validated) { + return@apply } - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) + known() + validated = true } - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } /** - * Returns an immutable instance of [Transaction]. + * Returns a score indicating how many valid values are contained in this object + * recursively. * - * Further updates to this [Builder] will not mutate the returned instance. + * Used for best match union deserialization. */ - fun build(): Transaction = - Transaction( - amount, - balance, - date, - description, - dividendRate, - nav, - type, - units, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Transaction = apply { - if (validated) { - return@apply - } + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - amount() - balance() - date() - description() - dividendRate() - nav() - type() - units() - validated = true - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false + return other is Tier && value == other.value } - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (amount.asKnown().isPresent) 1 else 0) + - (if (balance.asKnown().isPresent) 1 else 0) + - (if (date.asKnown().isPresent) 1 else 0) + - (if (description.asKnown().isPresent) 1 else 0) + - (if (dividendRate.asKnown().isPresent) 1 else 0) + - (if (nav.asKnown().isPresent) 1 else 0) + - (if (type.asKnown().isPresent) 1 else 0) + - (if (units.asKnown().isPresent) 1 else 0) + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Transaction && - amount == other.amount && - balance == other.balance && - date == other.date && - description == other.description && - dividendRate == other.dividendRate && - nav == other.nav && - type == other.type && - units == other.units && + return other is AdditionalInfo && + manager == other.manager && + tier == other.tier && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash( - amount, - balance, - date, - description, - dividendRate, - nav, - type, - units, - additionalProperties, - ) + Objects.hash(manager, tier, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Transaction{amount=$amount, balance=$balance, date=$date, description=$description, dividendRate=$dividendRate, nav=$nav, type=$type, units=$units, additionalProperties=$additionalProperties}" + "AdditionalInfo{manager=$manager, tier=$tier, additionalProperties=$additionalProperties}" } - /** Type of mutual fund scheme */ - class Type @JsonCreator private constructor(private val value: JsonField) : - Enum { + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that - * doesn't match any known 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. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + return other is Fund && + additionalInfo == other.additionalInfo && + cost == other.cost && + name == other.name && + nav == other.nav && + units == other.units && + value == other.value && + additionalProperties == other.additionalProperties + } - companion object { + private val hashCode: Int by lazy { + Objects.hash(additionalInfo, cost, name, nav, units, value, additionalProperties) + } - @JvmField val EQUITY = of("Equity") + override fun hashCode(): Int = hashCode - @JvmField val DEBT = of("Debt") + override fun toString() = + "Fund{additionalInfo=$additionalInfo, cost=$cost, name=$name, nav=$nav, units=$units, value=$value, additionalProperties=$additionalProperties}" + } - @JvmField val HYBRID = of("Hybrid") + class LinkedHolder + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val pan: JsonField, + private val additionalProperties: MutableMap, + ) { - @JvmField val OTHER = of("Other") + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("pan") @ExcludeMissing pan: JsonField = JsonMissing.of(), + ) : this(name, pan, mutableMapOf()) - @JvmStatic fun of(value: String) = Type(JsonField.of(value)) - } + /** + * Name of the account holder + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") - /** An enum containing [Type]'s known values. */ - enum class Known { - EQUITY, - DEBT, - HYBRID, - OTHER, - } + /** + * PAN of the account holder + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun pan(): Optional = pan.getOptional("pan") - /** - * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Type] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. 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. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - EQUITY, - DEBT, - HYBRID, - OTHER, - /** - * An enum member indicating that [Type] was instantiated with an unknown value. - */ - _UNKNOWN, + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [pan]. + * + * Unlike [pan], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pan") @ExcludeMissing fun _pan(): JsonField = pan + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [LinkedHolder]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [LinkedHolder]. */ + class Builder internal constructor() { + + private var name: JsonField = JsonMissing.of() + private var pan: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(linkedHolder: LinkedHolder) = apply { + name = linkedHolder.name + pan = linkedHolder.pan + additionalProperties = linkedHolder.additionalProperties.toMutableMap() } - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if - * you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - EQUITY -> Value.EQUITY - DEBT -> Value.DEBT - HYBRID -> Value.HYBRID - OTHER -> Value.OTHER - else -> Value._UNKNOWN - } + /** Name of the account holder */ + fun name(name: String) = name(JsonField.of(name)) /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and - * don't want to throw for the unknown case. + * Sets [Builder.name] to an arbitrary JSON value. * - * @throws CasParserInvalidDataException if this class instance's value is a not a - * known member. + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun known(): Known = - when (this) { - EQUITY -> Known.EQUITY - DEBT -> Known.DEBT - HYBRID -> Known.HYBRID - OTHER -> Known.OTHER - else -> throw CasParserInvalidDataException("Unknown Type: $value") - } + fun name(name: JsonField) = apply { this.name = name } + + /** PAN of the account holder */ + fun pan(pan: String) = pan(JsonField.of(pan)) /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. + * Sets [Builder.pan] to an arbitrary JSON value. * - * @throws CasParserInvalidDataException if this class instance's value does not - * have the expected primitive type. + * You should usually call [Builder.pan] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun asString(): String = - _value().asString().orElseThrow { - CasParserInvalidDataException("Value is not a String") - } + fun pan(pan: JsonField) = apply { this.pan = pan } - private var validated: Boolean = false + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun validate(): Type = apply { - if (validated) { - return@apply + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) } - known() - validated = true + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) } - fun isValid(): Boolean = - try { - validate() - true - } catch (e: CasParserInvalidDataException) { - false - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } /** - * Returns a score indicating how many valid values are contained in this object - * recursively. + * Returns an immutable instance of [LinkedHolder]. * - * Used for best match union deserialization. + * Further updates to this [Builder] will not mutate the returned instance. */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + fun build(): LinkedHolder = + LinkedHolder(name, pan, additionalProperties.toMutableMap()) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is Type && value == other.value + fun validate(): LinkedHolder = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + name() + pan() + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (name.asKnown().isPresent) 1 else 0) + (if (pan.asKnown().isPresent) 1 else 0) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Scheme && - additionalInfo == other.additionalInfo && - cost == other.cost && - gain == other.gain && - isin == other.isin && + return other is LinkedHolder && name == other.name && - nav == other.nav && - nominees == other.nominees && - transactions == other.transactions && - type == other.type && - units == other.units && - value == other.value && + pan == other.pan && additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { - Objects.hash( - additionalInfo, - cost, - gain, - isin, - name, - nav, - nominees, - transactions, - type, - units, - value, - additionalProperties, - ) - } + private val hashCode: Int by lazy { Objects.hash(name, pan, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Scheme{additionalInfo=$additionalInfo, cost=$cost, gain=$gain, isin=$isin, name=$name, nav=$nav, nominees=$nominees, transactions=$transactions, type=$type, units=$units, value=$value, additionalProperties=$additionalProperties}" + "LinkedHolder{name=$name, pan=$pan, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { @@ -6964,12 +17091,12 @@ private constructor( return true } - return other is MutualFund && + return other is Np && additionalInfo == other.additionalInfo && - amc == other.amc && - folioNumber == other.folioNumber && - registrar == other.registrar && - schemes == other.schemes && + cra == other.cra && + funds == other.funds && + linkedHolders == other.linkedHolders && + pran == other.pran && value == other.value && additionalProperties == other.additionalProperties } @@ -6977,10 +17104,10 @@ private constructor( private val hashCode: Int by lazy { Objects.hash( additionalInfo, - amc, - folioNumber, - registrar, - schemes, + cra, + funds, + linkedHolders, + pran, value, additionalProperties, ) @@ -6989,10 +17116,11 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "MutualFund{additionalInfo=$additionalInfo, amc=$amc, folioNumber=$folioNumber, registrar=$registrar, schemes=$schemes, value=$value, additionalProperties=$additionalProperties}" + "Np{additionalInfo=$additionalInfo, cra=$cra, funds=$funds, linkedHolders=$linkedHolders, pran=$pran, value=$value, additionalProperties=$additionalProperties}" } class Summary + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val accounts: JsonField, private val totalValue: JsonField, @@ -7154,10 +17282,12 @@ private constructor( (if (totalValue.asKnown().isPresent) 1 else 0) class Accounts + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val demat: JsonField, private val insurance: JsonField, private val mutualFunds: JsonField, + private val nps: JsonField, private val additionalProperties: MutableMap, ) { @@ -7170,7 +17300,8 @@ private constructor( @JsonProperty("mutual_funds") @ExcludeMissing mutualFunds: JsonField = JsonMissing.of(), - ) : this(demat, insurance, mutualFunds, mutableMapOf()) + @JsonProperty("nps") @ExcludeMissing nps: JsonField = JsonMissing.of(), + ) : this(demat, insurance, mutualFunds, nps, mutableMapOf()) /** * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. @@ -7190,6 +17321,12 @@ private constructor( */ fun mutualFunds(): Optional = mutualFunds.getOptional("mutual_funds") + /** + * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun nps(): Optional = nps.getOptional("nps") + /** * Returns the raw JSON value of [demat]. * @@ -7217,6 +17354,13 @@ private constructor( @ExcludeMissing fun _mutualFunds(): JsonField = mutualFunds + /** + * Returns the raw JSON value of [nps]. + * + * Unlike [nps], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("nps") @ExcludeMissing fun _nps(): JsonField = nps + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -7241,6 +17385,7 @@ private constructor( private var demat: JsonField = JsonMissing.of() private var insurance: JsonField = JsonMissing.of() private var mutualFunds: JsonField = JsonMissing.of() + private var nps: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -7248,6 +17393,7 @@ private constructor( demat = accounts.demat insurance = accounts.insurance mutualFunds = accounts.mutualFunds + nps = accounts.nps additionalProperties = accounts.additionalProperties.toMutableMap() } @@ -7288,6 +17434,17 @@ private constructor( this.mutualFunds = mutualFunds } + fun nps(nps: Nps) = nps(JsonField.of(nps)) + + /** + * Sets [Builder.nps] to an arbitrary JSON value. + * + * You should usually call [Builder.nps] with a well-typed [Nps] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun nps(nps: JsonField) = apply { this.nps = nps } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -7316,7 +17473,13 @@ private constructor( * Further updates to this [Builder] will not mutate the returned instance. */ fun build(): Accounts = - Accounts(demat, insurance, mutualFunds, additionalProperties.toMutableMap()) + Accounts( + demat, + insurance, + mutualFunds, + nps, + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -7329,6 +17492,7 @@ private constructor( demat().ifPresent { it.validate() } insurance().ifPresent { it.validate() } mutualFunds().ifPresent { it.validate() } + nps().ifPresent { it.validate() } validated = true } @@ -7350,9 +17514,11 @@ private constructor( internal fun validity(): Int = (demat.asKnown().getOrNull()?.validity() ?: 0) + (insurance.asKnown().getOrNull()?.validity() ?: 0) + - (mutualFunds.asKnown().getOrNull()?.validity() ?: 0) + (mutualFunds.asKnown().getOrNull()?.validity() ?: 0) + + (nps.asKnown().getOrNull()?.validity() ?: 0) class Demat + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val count: JsonField, private val totalValue: JsonField, @@ -7545,6 +17711,7 @@ private constructor( } class Insurance + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val count: JsonField, private val totalValue: JsonField, @@ -7737,6 +17904,7 @@ private constructor( } class MutualFunds + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val count: JsonField, private val totalValue: JsonField, @@ -7928,6 +18096,198 @@ private constructor( "MutualFunds{count=$count, totalValue=$totalValue, additionalProperties=$additionalProperties}" } + class Nps + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val count: JsonField, + private val totalValue: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("count") + @ExcludeMissing + count: JsonField = JsonMissing.of(), + @JsonProperty("total_value") + @ExcludeMissing + totalValue: JsonField = JsonMissing.of(), + ) : this(count, totalValue, mutableMapOf()) + + /** + * Number of NPS accounts + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun count(): Optional = count.getOptional("count") + + /** + * Total value of NPS accounts + * + * @throws CasParserInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun totalValue(): Optional = totalValue.getOptional("total_value") + + /** + * Returns the raw JSON value of [count]. + * + * Unlike [count], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("count") @ExcludeMissing fun _count(): JsonField = count + + /** + * Returns the raw JSON value of [totalValue]. + * + * Unlike [totalValue], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("total_value") + @ExcludeMissing + fun _totalValue(): JsonField = totalValue + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Nps]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Nps]. */ + class Builder internal constructor() { + + private var count: JsonField = JsonMissing.of() + private var totalValue: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(nps: Nps) = apply { + count = nps.count + totalValue = nps.totalValue + additionalProperties = nps.additionalProperties.toMutableMap() + } + + /** Number of NPS accounts */ + fun count(count: Long) = count(JsonField.of(count)) + + /** + * Sets [Builder.count] to an arbitrary JSON value. + * + * You should usually call [Builder.count] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun count(count: JsonField) = apply { this.count = count } + + /** Total value of NPS accounts */ + fun totalValue(totalValue: Float) = totalValue(JsonField.of(totalValue)) + + /** + * Sets [Builder.totalValue] to an arbitrary JSON value. + * + * You should usually call [Builder.totalValue] with a well-typed [Float] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun totalValue(totalValue: JsonField) = apply { + this.totalValue = totalValue + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Nps]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Nps = Nps(count, totalValue, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Nps = apply { + if (validated) { + return@apply + } + + count() + totalValue() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: CasParserInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (count.asKnown().isPresent) 1 else 0) + + (if (totalValue.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Nps && + count == other.count && + totalValue == other.totalValue && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(count, totalValue, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Nps{count=$count, totalValue=$totalValue, additionalProperties=$additionalProperties}" + } + override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -7937,17 +18297,18 @@ private constructor( demat == other.demat && insurance == other.insurance && mutualFunds == other.mutualFunds && + nps == other.nps && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(demat, insurance, mutualFunds, additionalProperties) + Objects.hash(demat, insurance, mutualFunds, nps, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Accounts{demat=$demat, insurance=$insurance, mutualFunds=$mutualFunds, additionalProperties=$additionalProperties}" + "Accounts{demat=$demat, insurance=$insurance, mutualFunds=$mutualFunds, nps=$nps, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { @@ -7982,6 +18343,7 @@ private constructor( investor == other.investor && meta == other.meta && mutualFunds == other.mutualFunds && + nps == other.nps && summary == other.summary && additionalProperties == other.additionalProperties } @@ -7993,6 +18355,7 @@ private constructor( investor, meta, mutualFunds, + nps, summary, additionalProperties, ) @@ -8001,5 +18364,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "UnifiedResponse{dematAccounts=$dematAccounts, insurance=$insurance, investor=$investor, meta=$meta, mutualFunds=$mutualFunds, summary=$summary, additionalProperties=$additionalProperties}" + "UnifiedResponse{dematAccounts=$dematAccounts, insurance=$insurance, investor=$investor, meta=$meta, mutualFunds=$mutualFunds, nps=$nps, summary=$summary, additionalProperties=$additionalProperties}" } diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/async/CasGeneratorServiceAsync.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/async/CasGeneratorServiceAsync.kt index 9eee1d4..0e6995d 100644 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/async/CasGeneratorServiceAsync.kt +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/async/CasGeneratorServiceAsync.kt @@ -3,11 +3,6 @@ package com.cas_parser.api.services.async import com.cas_parser.api.core.ClientOptions -import com.cas_parser.api.core.RequestOptions -import com.cas_parser.api.core.http.HttpResponseFor -import com.cas_parser.api.models.casgenerator.CasGeneratorGenerateCasParams -import com.cas_parser.api.models.casgenerator.CasGeneratorGenerateCasResponse -import java.util.concurrent.CompletableFuture import java.util.function.Consumer interface CasGeneratorServiceAsync { @@ -24,22 +19,6 @@ interface CasGeneratorServiceAsync { */ fun withOptions(modifier: Consumer): CasGeneratorServiceAsync - /** - * This endpoint generates CAS (Consolidated Account Statement) documents by submitting a - * mailback request to the specified CAS authority. Currently only supports KFintech, with plans - * to support CAMS, CDSL, and NSDL in the future. - */ - fun generateCas( - params: CasGeneratorGenerateCasParams - ): CompletableFuture = - generateCas(params, RequestOptions.none()) - - /** @see generateCas */ - fun generateCas( - params: CasGeneratorGenerateCasParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture - /** * A view of [CasGeneratorServiceAsync] that provides access to raw HTTP responses for each * method. @@ -54,20 +33,5 @@ interface CasGeneratorServiceAsync { fun withOptions( modifier: Consumer ): CasGeneratorServiceAsync.WithRawResponse - - /** - * Returns a raw HTTP response for `post /v4/generate`, but is otherwise the same as - * [CasGeneratorServiceAsync.generateCas]. - */ - fun generateCas( - params: CasGeneratorGenerateCasParams - ): CompletableFuture> = - generateCas(params, RequestOptions.none()) - - /** @see generateCas */ - fun generateCas( - params: CasGeneratorGenerateCasParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> } } diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/async/CasGeneratorServiceAsyncImpl.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/async/CasGeneratorServiceAsyncImpl.kt index b0b1ff9..0bbd145 100644 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/async/CasGeneratorServiceAsyncImpl.kt +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/async/CasGeneratorServiceAsyncImpl.kt @@ -3,21 +3,6 @@ package com.cas_parser.api.services.async import com.cas_parser.api.core.ClientOptions -import com.cas_parser.api.core.RequestOptions -import com.cas_parser.api.core.handlers.errorBodyHandler -import com.cas_parser.api.core.handlers.errorHandler -import com.cas_parser.api.core.handlers.jsonHandler -import com.cas_parser.api.core.http.HttpMethod -import com.cas_parser.api.core.http.HttpRequest -import com.cas_parser.api.core.http.HttpResponse -import com.cas_parser.api.core.http.HttpResponse.Handler -import com.cas_parser.api.core.http.HttpResponseFor -import com.cas_parser.api.core.http.json -import com.cas_parser.api.core.http.parseable -import com.cas_parser.api.core.prepareAsync -import com.cas_parser.api.models.casgenerator.CasGeneratorGenerateCasParams -import com.cas_parser.api.models.casgenerator.CasGeneratorGenerateCasResponse -import java.util.concurrent.CompletableFuture import java.util.function.Consumer class CasGeneratorServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : @@ -32,55 +17,14 @@ class CasGeneratorServiceAsyncImpl internal constructor(private val clientOption override fun withOptions(modifier: Consumer): CasGeneratorServiceAsync = CasGeneratorServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) - override fun generateCas( - params: CasGeneratorGenerateCasParams, - requestOptions: RequestOptions, - ): CompletableFuture = - // post /v4/generate - withRawResponse().generateCas(params, requestOptions).thenApply { it.parse() } - class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : CasGeneratorServiceAsync.WithRawResponse { - private val errorHandler: Handler = - errorHandler(errorBodyHandler(clientOptions.jsonMapper)) - override fun withOptions( modifier: Consumer ): CasGeneratorServiceAsync.WithRawResponse = CasGeneratorServiceAsyncImpl.WithRawResponseImpl( clientOptions.toBuilder().apply(modifier::accept).build() ) - - private val generateCasHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - - override fun generateCas( - params: CasGeneratorGenerateCasParams, - requestOptions: RequestOptions, - ): CompletableFuture> { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("v4", "generate") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepareAsync(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - return request - .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } - .thenApply { response -> - errorHandler.handle(response).parseable { - response - .use { generateCasHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - } - } - } } } diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/blocking/CasGeneratorService.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/blocking/CasGeneratorService.kt index b586008..f0ad062 100644 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/blocking/CasGeneratorService.kt +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/blocking/CasGeneratorService.kt @@ -3,11 +3,6 @@ package com.cas_parser.api.services.blocking import com.cas_parser.api.core.ClientOptions -import com.cas_parser.api.core.RequestOptions -import com.cas_parser.api.core.http.HttpResponseFor -import com.cas_parser.api.models.casgenerator.CasGeneratorGenerateCasParams -import com.cas_parser.api.models.casgenerator.CasGeneratorGenerateCasResponse -import com.google.errorprone.annotations.MustBeClosed import java.util.function.Consumer interface CasGeneratorService { @@ -24,20 +19,6 @@ interface CasGeneratorService { */ fun withOptions(modifier: Consumer): CasGeneratorService - /** - * This endpoint generates CAS (Consolidated Account Statement) documents by submitting a - * mailback request to the specified CAS authority. Currently only supports KFintech, with plans - * to support CAMS, CDSL, and NSDL in the future. - */ - fun generateCas(params: CasGeneratorGenerateCasParams): CasGeneratorGenerateCasResponse = - generateCas(params, RequestOptions.none()) - - /** @see generateCas */ - fun generateCas( - params: CasGeneratorGenerateCasParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CasGeneratorGenerateCasResponse - /** * A view of [CasGeneratorService] that provides access to raw HTTP responses for each method. */ @@ -51,22 +32,5 @@ interface CasGeneratorService { fun withOptions( modifier: Consumer ): CasGeneratorService.WithRawResponse - - /** - * Returns a raw HTTP response for `post /v4/generate`, but is otherwise the same as - * [CasGeneratorService.generateCas]. - */ - @MustBeClosed - fun generateCas( - params: CasGeneratorGenerateCasParams - ): HttpResponseFor = - generateCas(params, RequestOptions.none()) - - /** @see generateCas */ - @MustBeClosed - fun generateCas( - params: CasGeneratorGenerateCasParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor } } diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/blocking/CasGeneratorServiceImpl.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/blocking/CasGeneratorServiceImpl.kt index 26bcfb5..1d0054b 100644 --- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/blocking/CasGeneratorServiceImpl.kt +++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/services/blocking/CasGeneratorServiceImpl.kt @@ -3,20 +3,6 @@ package com.cas_parser.api.services.blocking import com.cas_parser.api.core.ClientOptions -import com.cas_parser.api.core.RequestOptions -import com.cas_parser.api.core.handlers.errorBodyHandler -import com.cas_parser.api.core.handlers.errorHandler -import com.cas_parser.api.core.handlers.jsonHandler -import com.cas_parser.api.core.http.HttpMethod -import com.cas_parser.api.core.http.HttpRequest -import com.cas_parser.api.core.http.HttpResponse -import com.cas_parser.api.core.http.HttpResponse.Handler -import com.cas_parser.api.core.http.HttpResponseFor -import com.cas_parser.api.core.http.json -import com.cas_parser.api.core.http.parseable -import com.cas_parser.api.core.prepare -import com.cas_parser.api.models.casgenerator.CasGeneratorGenerateCasParams -import com.cas_parser.api.models.casgenerator.CasGeneratorGenerateCasResponse import java.util.function.Consumer class CasGeneratorServiceImpl internal constructor(private val clientOptions: ClientOptions) : @@ -31,52 +17,14 @@ class CasGeneratorServiceImpl internal constructor(private val clientOptions: Cl override fun withOptions(modifier: Consumer): CasGeneratorService = CasGeneratorServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) - override fun generateCas( - params: CasGeneratorGenerateCasParams, - requestOptions: RequestOptions, - ): CasGeneratorGenerateCasResponse = - // post /v4/generate - withRawResponse().generateCas(params, requestOptions).parse() - class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : CasGeneratorService.WithRawResponse { - private val errorHandler: Handler = - errorHandler(errorBodyHandler(clientOptions.jsonMapper)) - override fun withOptions( modifier: Consumer ): CasGeneratorService.WithRawResponse = CasGeneratorServiceImpl.WithRawResponseImpl( clientOptions.toBuilder().apply(modifier::accept).build() ) - - private val generateCasHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - - override fun generateCas( - params: CasGeneratorGenerateCasParams, - requestOptions: RequestOptions, - ): HttpResponseFor { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("v4", "generate") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepare(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - val response = clientOptions.httpClient.execute(request, requestOptions) - return errorHandler.handle(response).parseable { - response - .use { generateCasHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - } - } } } diff --git a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/core/ObjectMappersTest.kt b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/core/ObjectMappersTest.kt index c338d17..93a6a00 100644 --- a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/core/ObjectMappersTest.kt +++ b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/core/ObjectMappersTest.kt @@ -3,7 +3,7 @@ package com.cas_parser.api.core import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.exc.MismatchedInputException import com.fasterxml.jackson.module.kotlin.readValue -import java.time.LocalDateTime +import java.time.OffsetDateTime import kotlin.reflect.KClass import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.catchThrowable @@ -46,11 +46,7 @@ internal class ObjectMappersTest { val VALID_CONVERSIONS = listOf( FLOAT to DOUBLE, - FLOAT to INTEGER, - FLOAT to LONG, DOUBLE to FLOAT, - DOUBLE to INTEGER, - DOUBLE to LONG, INTEGER to FLOAT, INTEGER to DOUBLE, INTEGER to LONG, @@ -58,14 +54,6 @@ internal class ObjectMappersTest { LONG to DOUBLE, LONG to INTEGER, CLASS to MAP, - // These aren't actually valid, but coercion configs don't work for String until - // v2.14.0: https://github.com/FasterXML/jackson-databind/issues/3240 - // We currently test on v2.13.4. - BOOLEAN to STRING, - FLOAT to STRING, - DOUBLE to STRING, - INTEGER to STRING, - LONG to STRING, ) } } @@ -84,7 +72,7 @@ internal class ObjectMappersTest { } } - enum class LenientLocalDateTimeTestCase(val string: String) { + enum class LenientOffsetDateTimeTestCase(val string: String) { DATE("1998-04-21"), DATE_TIME("1998-04-21T04:00:00"), ZONED_DATE_TIME_1("1998-04-21T04:00:00+03:00"), @@ -93,10 +81,10 @@ internal class ObjectMappersTest { @ParameterizedTest @EnumSource - fun readLocalDateTime_lenient(testCase: LenientLocalDateTimeTestCase) { + fun readOffsetDateTime_lenient(testCase: LenientOffsetDateTimeTestCase) { val jsonMapper = jsonMapper() val json = jsonMapper.writeValueAsString(testCase.string) - assertDoesNotThrow { jsonMapper().readValue(json) } + assertDoesNotThrow { jsonMapper().readValue(json) } } } diff --git a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/core/http/HttpRequestTest.kt b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/core/http/HttpRequestTest.kt new file mode 100644 index 0000000..06e315d --- /dev/null +++ b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/core/http/HttpRequestTest.kt @@ -0,0 +1,110 @@ +package com.cas_parser.api.core.http + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +internal class HttpRequestTest { + + enum class UrlTestCase(val request: HttpRequest, val expectedUrl: String) { + BASE_URL_ONLY( + HttpRequest.builder().method(HttpMethod.GET).baseUrl("https://api.example.com").build(), + expectedUrl = "https://api.example.com", + ), + BASE_URL_WITH_TRAILING_SLASH( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com/") + .build(), + expectedUrl = "https://api.example.com/", + ), + SINGLE_PATH_SEGMENT( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .build(), + expectedUrl = "https://api.example.com/users", + ), + MULTIPLE_PATH_SEGMENTS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegments("users", "123", "profile") + .build(), + expectedUrl = "https://api.example.com/users/123/profile", + ), + PATH_SEGMENT_WITH_SPECIAL_CHARS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("user name") + .build(), + expectedUrl = "https://api.example.com/user+name", + ), + SINGLE_QUERY_PARAM( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .putQueryParam("limit", "10") + .build(), + expectedUrl = "https://api.example.com/users?limit=10", + ), + MULTIPLE_QUERY_PARAMS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .putQueryParam("limit", "10") + .putQueryParam("offset", "20") + .build(), + expectedUrl = "https://api.example.com/users?limit=10&offset=20", + ), + QUERY_PARAM_WITH_SPECIAL_CHARS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("search") + .putQueryParam("q", "hello world") + .build(), + expectedUrl = "https://api.example.com/search?q=hello+world", + ), + MULTIPLE_VALUES_SAME_PARAM( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .putQueryParams("tags", listOf("admin", "user")) + .build(), + expectedUrl = "https://api.example.com/users?tags=admin&tags=user", + ), + BASE_URL_WITH_TRAILING_SLASH_AND_PATH( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com/") + .addPathSegment("users") + .build(), + expectedUrl = "https://api.example.com/users", + ), + COMPLEX_URL( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl("https://api.example.com") + .addPathSegments("v1", "users", "123") + .putQueryParams("include", listOf("profile", "settings")) + .putQueryParam("format", "json") + .build(), + expectedUrl = + "https://api.example.com/v1/users/123?include=profile&include=settings&format=json", + ), + } + + @ParameterizedTest + @EnumSource + fun url(testCase: UrlTestCase) { + val actualUrl = testCase.request.url() + + assertThat(actualUrl).isEqualTo(testCase.expectedUrl) + } +} diff --git a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/core/http/RetryingHttpClientTest.kt b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/core/http/RetryingHttpClientTest.kt index d740df3..90db8ea 100644 --- a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/core/http/RetryingHttpClientTest.kt +++ b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/core/http/RetryingHttpClientTest.kt @@ -2,6 +2,7 @@ package com.cas_parser.api.core.http import com.cas_parser.api.client.okhttp.OkHttpClient import com.cas_parser.api.core.RequestOptions +import com.cas_parser.api.core.Sleeper import com.cas_parser.api.errors.CasParserRetryableException import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo @@ -294,12 +295,14 @@ internal class RetryingHttpClientTest { .httpClient(failingHttpClient) .maxRetries(2) .sleeper( - object : RetryingHttpClient.Sleeper { + object : Sleeper { override fun sleep(duration: Duration) {} override fun sleepAsync(duration: Duration): CompletableFuture = CompletableFuture.completedFuture(null) + + override fun close() {} } ) .build() @@ -333,12 +336,14 @@ internal class RetryingHttpClientTest { .httpClient(httpClient) // Use a no-op `Sleeper` to make the test fast. .sleeper( - object : RetryingHttpClient.Sleeper { + object : Sleeper { override fun sleep(duration: Duration) {} override fun sleepAsync(duration: Duration): CompletableFuture = CompletableFuture.completedFuture(null) + + override fun close() {} } ) diff --git a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasParamsTest.kt b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasParamsTest.kt deleted file mode 100644 index 24f18c9..0000000 --- a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasParamsTest.kt +++ /dev/null @@ -1,62 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.cas_parser.api.models.casgenerator - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class CasGeneratorGenerateCasParamsTest { - - @Test - fun create() { - CasGeneratorGenerateCasParams.builder() - .email("user@example.com") - .fromDate("2023-01-01") - .password("Abcdefghi12\$") - .toDate("2023-12-31") - .casAuthority(CasGeneratorGenerateCasParams.CasAuthority.KFINTECH) - .panNo("ABCDE1234F") - .build() - } - - @Test - fun body() { - val params = - CasGeneratorGenerateCasParams.builder() - .email("user@example.com") - .fromDate("2023-01-01") - .password("Abcdefghi12\$") - .toDate("2023-12-31") - .casAuthority(CasGeneratorGenerateCasParams.CasAuthority.KFINTECH) - .panNo("ABCDE1234F") - .build() - - val body = params._body() - - assertThat(body.email()).isEqualTo("user@example.com") - assertThat(body.fromDate()).isEqualTo("2023-01-01") - assertThat(body.password()).isEqualTo("Abcdefghi12\$") - assertThat(body.toDate()).isEqualTo("2023-12-31") - assertThat(body.casAuthority()) - .contains(CasGeneratorGenerateCasParams.CasAuthority.KFINTECH) - assertThat(body.panNo()).contains("ABCDE1234F") - } - - @Test - fun bodyWithoutOptionalFields() { - val params = - CasGeneratorGenerateCasParams.builder() - .email("user@example.com") - .fromDate("2023-01-01") - .password("Abcdefghi12\$") - .toDate("2023-12-31") - .build() - - val body = params._body() - - assertThat(body.email()).isEqualTo("user@example.com") - assertThat(body.fromDate()).isEqualTo("2023-01-01") - assertThat(body.password()).isEqualTo("Abcdefghi12\$") - assertThat(body.toDate()).isEqualTo("2023-12-31") - } -} diff --git a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasResponseTest.kt b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasResponseTest.kt deleted file mode 100644 index c225afa..0000000 --- a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasResponseTest.kt +++ /dev/null @@ -1,49 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.cas_parser.api.models.casgenerator - -import com.cas_parser.api.core.jsonMapper -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class CasGeneratorGenerateCasResponseTest { - - @Test - fun create() { - val casGeneratorGenerateCasResponse = - CasGeneratorGenerateCasResponse.builder() - .msg( - "CAS generation request submitted successfully. The investor will receive the CAS file via email shortly." - ) - .status("success") - .build() - - assertThat(casGeneratorGenerateCasResponse.msg()) - .contains( - "CAS generation request submitted successfully. The investor will receive the CAS file via email shortly." - ) - assertThat(casGeneratorGenerateCasResponse.status()).contains("success") - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val casGeneratorGenerateCasResponse = - CasGeneratorGenerateCasResponse.builder() - .msg( - "CAS generation request submitted successfully. The investor will receive the CAS file via email shortly." - ) - .status("success") - .build() - - val roundtrippedCasGeneratorGenerateCasResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(casGeneratorGenerateCasResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedCasGeneratorGenerateCasResponse) - .isEqualTo(casGeneratorGenerateCasResponse) - } -} diff --git a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/models/casparser/UnifiedResponseTest.kt b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/models/casparser/UnifiedResponseTest.kt index 1a5cffc..f0fa2ca 100644 --- a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/models/casparser/UnifiedResponseTest.kt +++ b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/models/casparser/UnifiedResponseTest.kt @@ -40,36 +40,197 @@ internal class UnifiedResponseTest { UnifiedResponse.DematAccount.Holdings.builder() .addAif( UnifiedResponse.DematAccount.Holdings.Aif.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Aif.AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.Aif.Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Aif + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings.Aif + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addCorporateBond( UnifiedResponse.DematAccount.Holdings.CorporateBond.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.CorporateBond + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.CorporateBond + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings + .CorporateBond + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings + .CorporateBond + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addDematMutualFund( UnifiedResponse.DematAccount.Holdings.DematMutualFund.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.DematMutualFund + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.DematMutualFund + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings + .DematMutualFund + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings + .DematMutualFund + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addEquity( UnifiedResponse.DematAccount.Holdings.Equity.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Equity + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.Equity.Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Equity + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings.Equity + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() @@ -77,15 +238,63 @@ internal class UnifiedResponseTest { .addGovernmentSecurity( UnifiedResponse.DematAccount.Holdings.GovernmentSecurity .builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.GovernmentSecurity + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.GovernmentSecurity + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings + .GovernmentSecurity + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings + .GovernmentSecurity + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .build() ) + .addLinkedHolder( + UnifiedResponse.DematAccount.LinkedHolder.builder() + .name("name") + .pan("pan") + .build() + ) .value(0.0f) .build() ) @@ -140,6 +349,12 @@ internal class UnifiedResponseTest { ) .amc("amc") .folioNumber("folio_number") + .addLinkedHolder( + UnifiedResponse.MutualFund.LinkedHolder.builder() + .name("name") + .pan("pan") + .build() + ) .registrar("registrar") .addScheme( UnifiedResponse.MutualFund.Scheme.builder() @@ -165,13 +380,29 @@ internal class UnifiedResponseTest { .addNominee("string") .addTransaction( UnifiedResponse.MutualFund.Scheme.Transaction.builder() + .additionalInfo( + UnifiedResponse.MutualFund.Scheme.Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) .amount(0.0f) .balance(0.0f) .date(LocalDate.parse("2019-12-27")) .description("description") .dividendRate(0.0f) .nav(0.0f) - .type("type") + .type( + UnifiedResponse.MutualFund.Scheme.Transaction.Type + .PURCHASE + ) .units(0.0f) .build() ) @@ -183,6 +414,35 @@ internal class UnifiedResponseTest { .value(0.0f) .build() ) + .addNp( + UnifiedResponse.Np.builder() + .additionalInfo(JsonValue.from(mapOf())) + .cra("cra") + .addFund( + UnifiedResponse.Np.Fund.builder() + .additionalInfo( + UnifiedResponse.Np.Fund.AdditionalInfo.builder() + .manager("manager") + .tier(UnifiedResponse.Np.Fund.AdditionalInfo.Tier._1) + .build() + ) + .cost(0.0f) + .name("name") + .nav(0.0f) + .units(0.0f) + .value(0.0f) + .build() + ) + .addLinkedHolder( + UnifiedResponse.Np.LinkedHolder.builder() + .name("name") + .pan("pan") + .build() + ) + .pran("pran") + .value(0.0f) + .build() + ) .summary( UnifiedResponse.Summary.builder() .accounts( @@ -205,6 +465,12 @@ internal class UnifiedResponseTest { .totalValue(0.0f) .build() ) + .nps( + UnifiedResponse.Summary.Accounts.Nps.builder() + .count(0L) + .totalValue(0.0f) + .build() + ) .build() ) .totalValue(0.0f) @@ -236,51 +502,257 @@ internal class UnifiedResponseTest { UnifiedResponse.DematAccount.Holdings.builder() .addAif( UnifiedResponse.DematAccount.Holdings.Aif.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Aif.AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.Aif.Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Aif + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings.Aif + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addCorporateBond( UnifiedResponse.DematAccount.Holdings.CorporateBond.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.CorporateBond + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.CorporateBond + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.CorporateBond + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings.CorporateBond + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addDematMutualFund( UnifiedResponse.DematAccount.Holdings.DematMutualFund.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.DematMutualFund + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.DematMutualFund + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings + .DematMutualFund + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings + .DematMutualFund + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addEquity( UnifiedResponse.DematAccount.Holdings.Equity.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Equity.AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.Equity.Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Equity + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings.Equity + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addGovernmentSecurity( UnifiedResponse.DematAccount.Holdings.GovernmentSecurity.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.GovernmentSecurity + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.GovernmentSecurity + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings + .GovernmentSecurity + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings + .GovernmentSecurity + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .build() ) + .addLinkedHolder( + UnifiedResponse.DematAccount.LinkedHolder.builder() + .name("name") + .pan("pan") + .build() + ) .value(0.0f) .build() ) @@ -339,6 +811,12 @@ internal class UnifiedResponseTest { ) .amc("amc") .folioNumber("folio_number") + .addLinkedHolder( + UnifiedResponse.MutualFund.LinkedHolder.builder() + .name("name") + .pan("pan") + .build() + ) .registrar("registrar") .addScheme( UnifiedResponse.MutualFund.Scheme.builder() @@ -364,13 +842,27 @@ internal class UnifiedResponseTest { .addNominee("string") .addTransaction( UnifiedResponse.MutualFund.Scheme.Transaction.builder() + .additionalInfo( + UnifiedResponse.MutualFund.Scheme.Transaction.AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) .amount(0.0f) .balance(0.0f) .date(LocalDate.parse("2019-12-27")) .description("description") .dividendRate(0.0f) .nav(0.0f) - .type("type") + .type( + UnifiedResponse.MutualFund.Scheme.Transaction.Type.PURCHASE + ) .units(0.0f) .build() ) @@ -382,6 +874,33 @@ internal class UnifiedResponseTest { .value(0.0f) .build() ) + assertThat(unifiedResponse.nps().getOrNull()) + .containsExactly( + UnifiedResponse.Np.builder() + .additionalInfo(JsonValue.from(mapOf())) + .cra("cra") + .addFund( + UnifiedResponse.Np.Fund.builder() + .additionalInfo( + UnifiedResponse.Np.Fund.AdditionalInfo.builder() + .manager("manager") + .tier(UnifiedResponse.Np.Fund.AdditionalInfo.Tier._1) + .build() + ) + .cost(0.0f) + .name("name") + .nav(0.0f) + .units(0.0f) + .value(0.0f) + .build() + ) + .addLinkedHolder( + UnifiedResponse.Np.LinkedHolder.builder().name("name").pan("pan").build() + ) + .pran("pran") + .value(0.0f) + .build() + ) assertThat(unifiedResponse.summary()) .contains( UnifiedResponse.Summary.builder() @@ -405,6 +924,12 @@ internal class UnifiedResponseTest { .totalValue(0.0f) .build() ) + .nps( + UnifiedResponse.Summary.Accounts.Nps.builder() + .count(0L) + .totalValue(0.0f) + .build() + ) .build() ) .totalValue(0.0f) @@ -440,36 +965,197 @@ internal class UnifiedResponseTest { UnifiedResponse.DematAccount.Holdings.builder() .addAif( UnifiedResponse.DematAccount.Holdings.Aif.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Aif.AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.Aif.Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Aif + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings.Aif + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addCorporateBond( UnifiedResponse.DematAccount.Holdings.CorporateBond.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.CorporateBond + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.CorporateBond + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings + .CorporateBond + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings + .CorporateBond + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addDematMutualFund( UnifiedResponse.DematAccount.Holdings.DematMutualFund.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.DematMutualFund + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.DematMutualFund + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings + .DematMutualFund + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings + .DematMutualFund + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addEquity( UnifiedResponse.DematAccount.Holdings.Equity.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Equity + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.Equity.Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Equity + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings.Equity + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() @@ -477,15 +1163,63 @@ internal class UnifiedResponseTest { .addGovernmentSecurity( UnifiedResponse.DematAccount.Holdings.GovernmentSecurity .builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.GovernmentSecurity + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.GovernmentSecurity + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings + .GovernmentSecurity + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings + .GovernmentSecurity + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .build() ) + .addLinkedHolder( + UnifiedResponse.DematAccount.LinkedHolder.builder() + .name("name") + .pan("pan") + .build() + ) .value(0.0f) .build() ) @@ -540,6 +1274,12 @@ internal class UnifiedResponseTest { ) .amc("amc") .folioNumber("folio_number") + .addLinkedHolder( + UnifiedResponse.MutualFund.LinkedHolder.builder() + .name("name") + .pan("pan") + .build() + ) .registrar("registrar") .addScheme( UnifiedResponse.MutualFund.Scheme.builder() @@ -565,13 +1305,29 @@ internal class UnifiedResponseTest { .addNominee("string") .addTransaction( UnifiedResponse.MutualFund.Scheme.Transaction.builder() + .additionalInfo( + UnifiedResponse.MutualFund.Scheme.Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) .amount(0.0f) .balance(0.0f) .date(LocalDate.parse("2019-12-27")) .description("description") .dividendRate(0.0f) .nav(0.0f) - .type("type") + .type( + UnifiedResponse.MutualFund.Scheme.Transaction.Type + .PURCHASE + ) .units(0.0f) .build() ) @@ -583,6 +1339,35 @@ internal class UnifiedResponseTest { .value(0.0f) .build() ) + .addNp( + UnifiedResponse.Np.builder() + .additionalInfo(JsonValue.from(mapOf())) + .cra("cra") + .addFund( + UnifiedResponse.Np.Fund.builder() + .additionalInfo( + UnifiedResponse.Np.Fund.AdditionalInfo.builder() + .manager("manager") + .tier(UnifiedResponse.Np.Fund.AdditionalInfo.Tier._1) + .build() + ) + .cost(0.0f) + .name("name") + .nav(0.0f) + .units(0.0f) + .value(0.0f) + .build() + ) + .addLinkedHolder( + UnifiedResponse.Np.LinkedHolder.builder() + .name("name") + .pan("pan") + .build() + ) + .pran("pran") + .value(0.0f) + .build() + ) .summary( UnifiedResponse.Summary.builder() .accounts( @@ -605,6 +1390,12 @@ internal class UnifiedResponseTest { .totalValue(0.0f) .build() ) + .nps( + UnifiedResponse.Summary.Accounts.Nps.builder() + .count(0L) + .totalValue(0.0f) + .build() + ) .build() ) .totalValue(0.0f) diff --git a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/services/async/CasGeneratorServiceAsyncTest.kt b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/services/async/CasGeneratorServiceAsyncTest.kt deleted file mode 100644 index c74ed37..0000000 --- a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/services/async/CasGeneratorServiceAsyncTest.kt +++ /dev/null @@ -1,40 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.cas_parser.api.services.async - -import com.cas_parser.api.TestServerExtension -import com.cas_parser.api.client.okhttp.CasParserOkHttpClientAsync -import com.cas_parser.api.models.casgenerator.CasGeneratorGenerateCasParams -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith - -@ExtendWith(TestServerExtension::class) -internal class CasGeneratorServiceAsyncTest { - - @Disabled("Prism tests are disabled") - @Test - fun generateCas() { - val client = - CasParserOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() - val casGeneratorServiceAsync = client.casGenerator() - - val responseFuture = - casGeneratorServiceAsync.generateCas( - CasGeneratorGenerateCasParams.builder() - .email("user@example.com") - .fromDate("2023-01-01") - .password("Abcdefghi12\$") - .toDate("2023-12-31") - .casAuthority(CasGeneratorGenerateCasParams.CasAuthority.KFINTECH) - .panNo("ABCDE1234F") - .build() - ) - - val response = responseFuture.get() - response.validate() - } -} diff --git a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/services/blocking/CasGeneratorServiceTest.kt b/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/services/blocking/CasGeneratorServiceTest.kt deleted file mode 100644 index e66dcfb..0000000 --- a/cas-parser-java-core/src/test/kotlin/com/cas_parser/api/services/blocking/CasGeneratorServiceTest.kt +++ /dev/null @@ -1,39 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.cas_parser.api.services.blocking - -import com.cas_parser.api.TestServerExtension -import com.cas_parser.api.client.okhttp.CasParserOkHttpClient -import com.cas_parser.api.models.casgenerator.CasGeneratorGenerateCasParams -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith - -@ExtendWith(TestServerExtension::class) -internal class CasGeneratorServiceTest { - - @Disabled("Prism tests are disabled") - @Test - fun generateCas() { - val client = - CasParserOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() - val casGeneratorService = client.casGenerator() - - val response = - casGeneratorService.generateCas( - CasGeneratorGenerateCasParams.builder() - .email("user@example.com") - .fromDate("2023-01-01") - .password("Abcdefghi12\$") - .toDate("2023-12-31") - .casAuthority(CasGeneratorGenerateCasParams.CasAuthority.KFINTECH) - .panNo("ABCDE1234F") - .build() - ) - - response.validate() - } -} diff --git a/cas-parser-java-proguard-test/build.gradle.kts b/cas-parser-java-proguard-test/build.gradle.kts index de62f9c..bc6de2d 100644 --- a/cas-parser-java-proguard-test/build.gradle.kts +++ b/cas-parser-java-proguard-test/build.gradle.kts @@ -19,7 +19,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testImplementation("org.assertj:assertj-core:3.25.3") - testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") + testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.0") } tasks.shadowJar { diff --git a/cas-parser-java-proguard-test/src/test/kotlin/com/cas_parser/api/proguard/ProGuardCompatibilityTest.kt b/cas-parser-java-proguard-test/src/test/kotlin/com/cas_parser/api/proguard/ProGuardCompatibilityTest.kt index f132d1f..a975237 100644 --- a/cas-parser-java-proguard-test/src/test/kotlin/com/cas_parser/api/proguard/ProGuardCompatibilityTest.kt +++ b/cas-parser-java-proguard-test/src/test/kotlin/com/cas_parser/api/proguard/ProGuardCompatibilityTest.kt @@ -82,36 +82,197 @@ internal class ProGuardCompatibilityTest { UnifiedResponse.DematAccount.Holdings.builder() .addAif( UnifiedResponse.DematAccount.Holdings.Aif.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Aif.AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.Aif.Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Aif + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings.Aif + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addCorporateBond( UnifiedResponse.DematAccount.Holdings.CorporateBond.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.CorporateBond + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.CorporateBond + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings + .CorporateBond + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings + .CorporateBond + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addDematMutualFund( UnifiedResponse.DematAccount.Holdings.DematMutualFund.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.DematMutualFund + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.DematMutualFund + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings + .DematMutualFund + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings + .DematMutualFund + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .addEquity( UnifiedResponse.DematAccount.Holdings.Equity.builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Equity + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.Equity.Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.Equity + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings.Equity + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() @@ -119,15 +280,63 @@ internal class ProGuardCompatibilityTest { .addGovernmentSecurity( UnifiedResponse.DematAccount.Holdings.GovernmentSecurity .builder() - .additionalInfo(JsonValue.from(mapOf())) + .additionalInfo( + UnifiedResponse.DematAccount.Holdings.GovernmentSecurity + .AdditionalInfo + .builder() + .closeUnits(0.0f) + .openUnits(0.0f) + .build() + ) .isin("isin") .name("name") + .addTransaction( + UnifiedResponse.DematAccount.Holdings.GovernmentSecurity + .Transaction + .builder() + .additionalInfo( + UnifiedResponse.DematAccount.Holdings + .GovernmentSecurity + .Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) + .amount(0.0f) + .balance(0.0f) + .date(LocalDate.parse("2019-12-27")) + .description("description") + .dividendRate(0.0f) + .nav(0.0f) + .type( + UnifiedResponse.DematAccount.Holdings + .GovernmentSecurity + .Transaction + .Type + .PURCHASE + ) + .units(0.0f) + .build() + ) .units(0.0f) .value(0.0f) .build() ) .build() ) + .addLinkedHolder( + UnifiedResponse.DematAccount.LinkedHolder.builder() + .name("name") + .pan("pan") + .build() + ) .value(0.0f) .build() ) @@ -182,6 +391,12 @@ internal class ProGuardCompatibilityTest { ) .amc("amc") .folioNumber("folio_number") + .addLinkedHolder( + UnifiedResponse.MutualFund.LinkedHolder.builder() + .name("name") + .pan("pan") + .build() + ) .registrar("registrar") .addScheme( UnifiedResponse.MutualFund.Scheme.builder() @@ -207,13 +422,29 @@ internal class ProGuardCompatibilityTest { .addNominee("string") .addTransaction( UnifiedResponse.MutualFund.Scheme.Transaction.builder() + .additionalInfo( + UnifiedResponse.MutualFund.Scheme.Transaction + .AdditionalInfo + .builder() + .capitalWithdrawal(0.0f) + .credit(0.0f) + .debit(0.0f) + .incomeDistribution(0.0f) + .orderNo("order_no") + .price(0.0f) + .stampDuty(0.0f) + .build() + ) .amount(0.0f) .balance(0.0f) .date(LocalDate.parse("2019-12-27")) .description("description") .dividendRate(0.0f) .nav(0.0f) - .type("type") + .type( + UnifiedResponse.MutualFund.Scheme.Transaction.Type + .PURCHASE + ) .units(0.0f) .build() ) @@ -225,6 +456,35 @@ internal class ProGuardCompatibilityTest { .value(0.0f) .build() ) + .addNp( + UnifiedResponse.Np.builder() + .additionalInfo(JsonValue.from(mapOf())) + .cra("cra") + .addFund( + UnifiedResponse.Np.Fund.builder() + .additionalInfo( + UnifiedResponse.Np.Fund.AdditionalInfo.builder() + .manager("manager") + .tier(UnifiedResponse.Np.Fund.AdditionalInfo.Tier._1) + .build() + ) + .cost(0.0f) + .name("name") + .nav(0.0f) + .units(0.0f) + .value(0.0f) + .build() + ) + .addLinkedHolder( + UnifiedResponse.Np.LinkedHolder.builder() + .name("name") + .pan("pan") + .build() + ) + .pran("pran") + .value(0.0f) + .build() + ) .summary( UnifiedResponse.Summary.builder() .accounts( @@ -247,6 +507,12 @@ internal class ProGuardCompatibilityTest { .totalValue(0.0f) .build() ) + .nps( + UnifiedResponse.Summary.Accounts.Nps.builder() + .count(0L) + .totalValue(0.0f) + .build() + ) .build() ) .totalValue(0.0f) diff --git a/scripts/fast-format b/scripts/fast-format index e16bfc5..1b3bc47 100755 --- a/scripts/fast-format +++ b/scripts/fast-format @@ -2,7 +2,12 @@ set -euo pipefail +echo "Script started with $# arguments" +echo "Arguments: $*" +echo "Script location: $(dirname "$0")" + cd "$(dirname "$0")/.." +echo "Changed to directory: $(pwd)" if [ $# -eq 0 ]; then echo "Usage: $0 [additional-formatter-args...]" @@ -12,6 +17,8 @@ fi FILE_LIST="$1" +echo "Looking for file: $FILE_LIST" + if [ ! -f "$FILE_LIST" ]; then echo "Error: File '$FILE_LIST' not found" exit 1 @@ -23,9 +30,9 @@ if ! command -v ktfmt-fast-format &> /dev/null; then fi # Process Kotlin files -kt_files=$(grep -E '\.kt$' "$FILE_LIST" | grep -v './buildSrc/build/') -kt_files=$(grep -E '\.kt$' "$FILE_LIST" | grep -v './buildSrc/build/') -echo "==> Found $(echo "$kt_files" | wc -l) Kotlin files:" +echo "==> Looking for Kotlin files" +kt_files=$(grep -E '\.kt$' "$FILE_LIST" | grep -v './buildSrc/build/' || true) +echo "==> Done looking for Kotlin files" if [[ -n "$kt_files" ]]; then echo "==> will format Kotlin files" diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts new file mode 100755 index 0000000..548d152 --- /dev/null +++ b/scripts/upload-artifacts @@ -0,0 +1,139 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# ANSI Color Codes +GREEN='\033[32m' +RED='\033[31m' +NC='\033[0m' # No Color + +MAVEN_REPO_PATH="./build/local-maven-repo" + +log_error() { + local msg="$1" + local headers="$2" + local body="$3" + echo -e "${RED}${msg}${NC}" + [[ -f "$headers" ]] && echo -e "${RED}Headers:$(cat "$headers")${NC}" + echo -e "${RED}Body: ${body}${NC}" + exit 1 +} + +upload_file() { + local file_name="$1" + local tmp_headers + tmp_headers=$(mktemp) + + if [ -f "$file_name" ]; then + echo -e "${GREEN}Processing file: $file_name${NC}" + pkg_file_name="mvn${file_name#"${MAVEN_REPO_PATH}"}" + + # Get signed URL for uploading artifact file + signed_url_response=$(curl -X POST -G "$URL" \ + -sS --retry 5 \ + -D "$tmp_headers" \ + --data-urlencode "filename=$pkg_file_name" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + + # Validate JSON and extract URL + if ! signed_url=$(echo "$signed_url_response" | jq -e -r '.url' 2>/dev/null) || [[ "$signed_url" == "null" ]]; then + log_error "Failed to get valid signed URL" "$tmp_headers" "$signed_url_response" + fi + + # Set content-type based on file extension + local extension="${file_name##*.}" + local content_type + case "$extension" in + jar) content_type="application/java-archive" ;; + md5|sha1|sha256|sha512) content_type="text/plain" ;; + module) content_type="application/json" ;; + pom|xml) content_type="application/xml" ;; + html) content_type="text/html" ;; + *) content_type="application/octet-stream" ;; + esac + + # Upload file + upload_response=$(curl -v -X PUT \ + --retry 5 \ + --retry-all-errors \ + -D "$tmp_headers" \ + -H "Content-Type: $content_type" \ + --data-binary "@${file_name}" "$signed_url" 2>&1) + + if ! echo "$upload_response" | grep -q "HTTP/[0-9.]* 200"; then + log_error "Failed to upload artifact file" "$tmp_headers" "$upload_response" + fi + + # Insert small throttle to reduce rate limiting risk + sleep 0.1 + fi +} + +walk_tree() { + local current_dir="$1" + + for entry in "$current_dir"/*; do + # Check that entry is valid + [ -e "$entry" ] || [ -h "$entry" ] || continue + + if [ -d "$entry" ]; then + walk_tree "$entry" + else + upload_file "$entry" + fi + done +} + +generate_instructions() { + cat << EOF > "$MAVEN_REPO_PATH/index.html" + + + + Maven Repo + + +

Stainless SDK Maven Repository

+

This is the Maven repository for your Stainless Java SDK build.

+ +

Directions

+

To use the uploaded Maven repository, add the following to your project's pom.xml:

+
<repositories>
+    <repository>
+        <id>stainless-sdk-repo</id>
+        <url>https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn</url>
+    </repository>
+</repositories>
+ +

If you're using Gradle, add the following to your build.gradle file:

+
repositories {
+    maven {
+        url 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'
+    }
+}
+ +

Once you've added the repository, you can include dependencies from it as usual. See your + project README + for more details.

+ + +EOF + upload_file "${MAVEN_REPO_PATH}/index.html" + + echo "Configure maven or gradle to use the repo located at 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'" + echo "For more details, see the directions in https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn/index.html" +} + +cd "$(dirname "$0")/.." + +echo "::group::Creating local Maven content" +./gradlew publishMavenPublicationToLocalFileSystemRepository -PpublishLocal +echo "::endgroup::" + +echo "::group::Uploading to pkg.stainless.com" +walk_tree "$MAVEN_REPO_PATH" +echo "::endgroup::" + +echo "::group::Generating instructions" +generate_instructions +echo "::endgroup::"