From 900a6b205597d95620df418d01cd5cf43ccbaa04 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 25 Jun 2026 20:26:59 +0000 Subject: [PATCH 1/3] docs(types): clarify cash_amount description in CardAuthorization models --- .stats.yml | 4 ++-- .../lithic/api/models/CardAuthorization.kt | 20 +++++++++---------- ...uthorizationApprovalRequestWebhookEvent.kt | 20 +++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.stats.yml b/.stats.yml index d092e24ac..e05fda1e8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 214 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic/lithic-47e9f78d22682623e313f1689f5fa7e3420575ff285a14a2f4704c49ffb6b72e.yml -openapi_spec_hash: 4797fe46d942cb32e648a79015783d01 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic/lithic-d83e3ddb148bc0c81ff97bd31b82027d5b37efc110f5981103e7b9a2ae281c86.yml +openapi_spec_hash: f607b0571c4ed82a93a3df7bc9e9351b config_hash: 5bb913c05ebeb301ec925b16e75bb251 diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardAuthorization.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardAuthorization.kt index 1e5fb5060..8b4ed2b7d 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardAuthorization.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardAuthorization.kt @@ -243,12 +243,12 @@ private constructor( fun cardholderCurrency(): String = cardholderCurrency.getRequired("cardholder_currency") /** - * The portion of the transaction requested as cash back by the cardholder, and does not include - * any acquirer fees. The amount field includes the purchase amount, the requested cash back - * amount, and any acquirer fees. + * The amount of cash requested by the cardholder, in the cardholder billing currency's smallest + * unit. For purchase-with-cashback transactions this is the cashback portion only; for ATM + * transactions this is the full amount. This amount includes all acquirer fees. * - * If no cash back was requested, the value of this field will be 0, and the field will always - * be present. + * If no cash was requested, the value of this field will be 0, and the field will always be + * present. * * @throws LithicInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -957,12 +957,12 @@ private constructor( } /** - * The portion of the transaction requested as cash back by the cardholder, and does not - * include any acquirer fees. The amount field includes the purchase amount, the requested - * cash back amount, and any acquirer fees. + * The amount of cash requested by the cardholder, in the cardholder billing currency's + * smallest unit. For purchase-with-cashback transactions this is the cashback portion only; + * for ATM transactions this is the full amount. This amount includes all acquirer fees. * - * If no cash back was requested, the value of this field will be 0, and the field will - * always be present. + * If no cash was requested, the value of this field will be 0, and the field will always be + * present. */ fun cashAmount(cashAmount: Long) = cashAmount(JsonField.of(cashAmount)) diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardAuthorizationApprovalRequestWebhookEvent.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardAuthorizationApprovalRequestWebhookEvent.kt index c0908798a..a07ef8da1 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardAuthorizationApprovalRequestWebhookEvent.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CardAuthorizationApprovalRequestWebhookEvent.kt @@ -291,12 +291,12 @@ private constructor( fun cardholderCurrency(): String = cardholderCurrency.getRequired("cardholder_currency") /** - * The portion of the transaction requested as cash back by the cardholder, and does not include - * any acquirer fees. The amount field includes the purchase amount, the requested cash back - * amount, and any acquirer fees. + * The amount of cash requested by the cardholder, in the cardholder billing currency's smallest + * unit. For purchase-with-cashback transactions this is the cashback portion only; for ATM + * transactions this is the full amount. This amount includes all acquirer fees. * - * If no cash back was requested, the value of this field will be 0, and the field will always - * be present. + * If no cash was requested, the value of this field will be 0, and the field will always be + * present. * * @throws LithicInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -1045,12 +1045,12 @@ private constructor( } /** - * The portion of the transaction requested as cash back by the cardholder, and does not - * include any acquirer fees. The amount field includes the purchase amount, the requested - * cash back amount, and any acquirer fees. + * The amount of cash requested by the cardholder, in the cardholder billing currency's + * smallest unit. For purchase-with-cashback transactions this is the cashback portion only; + * for ATM transactions this is the full amount. This amount includes all acquirer fees. * - * If no cash back was requested, the value of this field will be 0, and the field will - * always be present. + * If no cash was requested, the value of this field will be 0, and the field will always be + * present. */ fun cashAmount(cashAmount: Long) = cashAmount(JsonField.of(cashAmount)) From 97a5e536cd0656291804ebda8b21d67ada4a1baf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 12:33:14 +0000 Subject: [PATCH 2/3] feat(types): convert CaseTransaction to union with card/payment variants --- .stats.yml | 4 +- .../com/lithic/api/models/CaseTransaction.kt | 1450 ++++++++++++++--- ...ctionMonitoringCaseListTransactionsPage.kt | 38 +- ...MonitoringCaseListTransactionsPageAsync.kt | 38 +- ...itoringCaseListTransactionsPageResponse.kt | 8 + .../lithic/api/models/CaseTransactionTest.kt | 94 +- ...ingCaseListTransactionsPageResponseTest.kt | 23 +- 7 files changed, 1381 insertions(+), 274 deletions(-) diff --git a/.stats.yml b/.stats.yml index e05fda1e8..189b2dd2a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 214 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic/lithic-d83e3ddb148bc0c81ff97bd31b82027d5b37efc110f5981103e7b9a2ae281c86.yml -openapi_spec_hash: f607b0571c4ed82a93a3df7bc9e9351b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic/lithic-9e397c65ffb81e2928b8ecf979769a79131ae6058b6fb373a5e930dc8a168732.yml +openapi_spec_hash: 93aea3855d2d1c390107d223762aa818 config_hash: 5bb913c05ebeb301ec925b16e75bb251 diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CaseTransaction.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CaseTransaction.kt index 8e3227c06..a5cc6e84a 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/CaseTransaction.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/CaseTransaction.kt @@ -6,354 +6,1314 @@ 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 com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.lithic.api.core.BaseDeserializer +import com.lithic.api.core.BaseSerializer +import com.lithic.api.core.Enum import com.lithic.api.core.ExcludeMissing import com.lithic.api.core.JsonField import com.lithic.api.core.JsonMissing import com.lithic.api.core.JsonValue +import com.lithic.api.core.allMaxBy import com.lithic.api.core.checkRequired +import com.lithic.api.core.getOrThrow import com.lithic.api.errors.LithicInvalidDataException import java.time.OffsetDateTime import java.util.Collections import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull -/** A single transaction associated with a case */ +/** + * A single transaction associated with a case. The `category` field identifies whether this is a + * card transaction or a payment transaction. + */ +@JsonDeserialize(using = CaseTransaction.Deserializer::class) +@JsonSerialize(using = CaseTransaction.Serializer::class) class CaseTransaction -@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val token: JsonField, - private val accountToken: JsonField, - private val addedAt: JsonField, - private val cardToken: JsonField, - private val transactionCreatedAt: JsonField, - private val additionalProperties: MutableMap, + private val card: CardCaseTransaction? = null, + private val payment: PaymentCaseTransaction? = null, + private val _json: JsonValue? = null, ) { - @JsonCreator - private constructor( - @JsonProperty("token") @ExcludeMissing token: JsonField = JsonMissing.of(), - @JsonProperty("account_token") - @ExcludeMissing - accountToken: JsonField = JsonMissing.of(), - @JsonProperty("added_at") - @ExcludeMissing - addedAt: JsonField = JsonMissing.of(), - @JsonProperty("card_token") @ExcludeMissing cardToken: JsonField = JsonMissing.of(), - @JsonProperty("transaction_created_at") - @ExcludeMissing - transactionCreatedAt: JsonField = JsonMissing.of(), - ) : this(token, accountToken, addedAt, cardToken, transactionCreatedAt, mutableMapOf()) + /** A card transaction associated with a case */ + fun card(): Optional = Optional.ofNullable(card) - /** - * Globally unique identifier for the transaction - * - * @throws LithicInvalidDataException 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 token(): String = token.getRequired("token") + /** A payment (ACH) transaction associated with a case */ + fun payment(): Optional = Optional.ofNullable(payment) - /** - * Token of the account the transaction belongs to - * - * @throws LithicInvalidDataException 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 accountToken(): String = accountToken.getRequired("account_token") + fun isCard(): Boolean = card != null - /** - * Date and time at which the transaction was added to the case - * - * @throws LithicInvalidDataException 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 addedAt(): OffsetDateTime = addedAt.getRequired("added_at") + fun isPayment(): Boolean = payment != null - /** - * Token of the card the transaction was made on - * - * @throws LithicInvalidDataException 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 cardToken(): String = cardToken.getRequired("card_token") + /** A card transaction associated with a case */ + fun asCard(): CardCaseTransaction = card.getOrThrow("card") - /** - * Date and time at which the transaction was created - * - * @throws LithicInvalidDataException 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 transactionCreatedAt(): OffsetDateTime = - transactionCreatedAt.getRequired("transaction_created_at") + /** A payment (ACH) transaction associated with a case */ + fun asPayment(): PaymentCaseTransaction = payment.getOrThrow("payment") - /** - * Returns the raw JSON value of [token]. - * - * Unlike [token], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("token") @ExcludeMissing fun _token(): JsonField = token + fun _json(): Optional = Optional.ofNullable(_json) /** - * Returns the raw JSON value of [accountToken]. + * Maps this instance's current variant to a value of type [T] using the given [visitor]. * - * Unlike [accountToken], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("account_token") - @ExcludeMissing - fun _accountToken(): JsonField = accountToken - - /** - * Returns the raw JSON value of [addedAt]. + * Note that this method is _not_ forwards compatible with new variants from the API, unless + * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of the + * SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.lithic.api.core.JsonValue; + * import java.util.Optional; * - * Unlike [addedAt], this method doesn't throw if the JSON field has an unexpected type. + * Optional result = caseTransaction.accept(new CaseTransaction.Visitor>() { + * @Override + * public Optional visitCard(CardCaseTransaction card) { + * return Optional.of(card.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws LithicInvalidDataException if [Visitor.unknown] is not overridden in [visitor] and + * the current variant is unknown. */ - @JsonProperty("added_at") @ExcludeMissing fun _addedAt(): JsonField = addedAt + fun accept(visitor: Visitor): T = + when { + card != null -> visitor.visitCard(card) + payment != null -> visitor.visitPayment(payment) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false /** - * Returns the raw JSON value of [cardToken]. + * Validates that the types of all values in this object match their expected types recursively. * - * Unlike [cardToken], this method doesn't throw if the JSON field has an unexpected type. + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws LithicInvalidDataException if any value type in this object doesn't match its + * expected type. */ - @JsonProperty("card_token") @ExcludeMissing fun _cardToken(): JsonField = cardToken + fun validate(): CaseTransaction = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitCard(card: CardCaseTransaction) { + card.validate() + } + + override fun visitPayment(payment: PaymentCaseTransaction) { + payment.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: LithicInvalidDataException) { + false + } /** - * Returns the raw JSON value of [transactionCreatedAt]. + * Returns a score indicating how many valid values are contained in this object recursively. * - * Unlike [transactionCreatedAt], this method doesn't throw if the JSON field has an unexpected - * type. + * Used for best match union deserialization. */ - @JsonProperty("transaction_created_at") - @ExcludeMissing - fun _transactionCreatedAt(): JsonField = transactionCreatedAt + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitCard(card: CardCaseTransaction) = card.validity() + + override fun visitPayment(payment: PaymentCaseTransaction) = payment.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) + return other is CaseTransaction && card == other.card && payment == other.payment } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + override fun hashCode(): Int = Objects.hash(card, payment) - fun toBuilder() = Builder().from(this) + override fun toString(): String = + when { + card != null -> "CaseTransaction{card=$card}" + payment != null -> "CaseTransaction{payment=$payment}" + _json != null -> "CaseTransaction{_unknown=$_json}" + else -> throw IllegalStateException("Invalid CaseTransaction") + } companion object { + /** A card transaction associated with a case */ + @JvmStatic fun ofCard(card: CardCaseTransaction) = CaseTransaction(card = card) + + /** A payment (ACH) transaction associated with a case */ + @JvmStatic + fun ofPayment(payment: PaymentCaseTransaction) = CaseTransaction(payment = payment) + } + + /** + * An interface that defines how to map each variant of [CaseTransaction] to a value of type + * [T]. + */ + interface Visitor { + + /** A card transaction associated with a case */ + fun visitCard(card: CardCaseTransaction): T + + /** A payment (ACH) transaction associated with a case */ + fun visitPayment(payment: PaymentCaseTransaction): T + /** - * Returns a mutable builder for constructing an instance of [CaseTransaction]. + * Maps an unknown variant of [CaseTransaction] to a value of type [T]. + * + * An instance of [CaseTransaction] can contain an unknown variant if it was deserialized + * from data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is unaware + * of. * - * The following fields are required: - * ```java - * .token() - * .accountToken() - * .addedAt() - * .cardToken() - * .transactionCreatedAt() - * ``` + * @throws LithicInvalidDataException in the default implementation. */ - @JvmStatic fun builder() = Builder() + fun unknown(json: JsonValue?): T { + throw LithicInvalidDataException("Unknown CaseTransaction: $json") + } } - /** A builder for [CaseTransaction]. */ - class Builder internal constructor() { + internal class Deserializer : BaseDeserializer(CaseTransaction::class) { - private var token: JsonField? = null - private var accountToken: JsonField? = null - private var addedAt: JsonField? = null - private var cardToken: JsonField? = null - private var transactionCreatedAt: JsonField? = null - private var additionalProperties: MutableMap = mutableMapOf() + override fun ObjectCodec.deserialize(node: JsonNode): CaseTransaction { + val json = JsonValue.fromJsonNode(node) + val category = json.asObject().getOrNull()?.get("category")?.asString()?.getOrNull() - @JvmSynthetic - internal fun from(caseTransaction: CaseTransaction) = apply { - token = caseTransaction.token - accountToken = caseTransaction.accountToken - addedAt = caseTransaction.addedAt - cardToken = caseTransaction.cardToken - transactionCreatedAt = caseTransaction.transactionCreatedAt - additionalProperties = caseTransaction.additionalProperties.toMutableMap() + when (category) {} + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + CaseTransaction(card = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + CaseTransaction(payment = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with all + // the possible variants (e.g. deserializing from boolean). + 0 -> CaseTransaction(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(CaseTransaction::class) { + + override fun serialize( + value: CaseTransaction, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.card != null -> generator.writeObject(value.card) + value.payment != null -> generator.writeObject(value.payment) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid CaseTransaction") + } } + } + + /** A card transaction associated with a case */ + class CardCaseTransaction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val token: JsonField, + private val accountToken: JsonField, + private val addedAt: JsonField, + private val cardToken: JsonField, + private val category: JsonField, + private val transactionCreatedAt: JsonField, + private val additionalProperties: MutableMap, + ) { - /** Globally unique identifier for the transaction */ - fun token(token: String) = token(JsonField.of(token)) + @JsonCreator + private constructor( + @JsonProperty("token") @ExcludeMissing token: JsonField = JsonMissing.of(), + @JsonProperty("account_token") + @ExcludeMissing + accountToken: JsonField = JsonMissing.of(), + @JsonProperty("added_at") + @ExcludeMissing + addedAt: JsonField = JsonMissing.of(), + @JsonProperty("card_token") + @ExcludeMissing + cardToken: JsonField = JsonMissing.of(), + @JsonProperty("category") + @ExcludeMissing + category: JsonField = JsonMissing.of(), + @JsonProperty("transaction_created_at") + @ExcludeMissing + transactionCreatedAt: JsonField = JsonMissing.of(), + ) : this( + token, + accountToken, + addedAt, + cardToken, + category, + transactionCreatedAt, + mutableMapOf(), + ) + + /** + * Globally unique identifier for the card transaction + * + * @throws LithicInvalidDataException 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 token(): String = token.getRequired("token") /** - * Sets [Builder.token] to an arbitrary JSON value. + * Token of the account the transaction belongs to * - * You should usually call [Builder.token] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. + * @throws LithicInvalidDataException 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 token(token: JsonField) = apply { this.token = token } + fun accountToken(): String = accountToken.getRequired("account_token") - /** Token of the account the transaction belongs to */ - fun accountToken(accountToken: String) = accountToken(JsonField.of(accountToken)) + /** + * Date and time at which the transaction was added to the case + * + * @throws LithicInvalidDataException 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 addedAt(): OffsetDateTime = addedAt.getRequired("added_at") /** - * Sets [Builder.accountToken] to an arbitrary JSON value. + * Token of the card the transaction was made on * - * You should usually call [Builder.accountToken] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. + * @throws LithicInvalidDataException 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 accountToken(accountToken: JsonField) = apply { - this.accountToken = accountToken - } + fun cardToken(): String = cardToken.getRequired("card_token") - /** Date and time at which the transaction was added to the case */ - fun addedAt(addedAt: OffsetDateTime) = addedAt(JsonField.of(addedAt)) + /** + * @throws LithicInvalidDataException 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 category(): Category = category.getRequired("category") /** - * Sets [Builder.addedAt] to an arbitrary JSON value. + * Date and time at which the transaction was created * - * You should usually call [Builder.addedAt] with a well-typed [OffsetDateTime] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. + * @throws LithicInvalidDataException 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 addedAt(addedAt: JsonField) = apply { this.addedAt = addedAt } + fun transactionCreatedAt(): OffsetDateTime = + transactionCreatedAt.getRequired("transaction_created_at") - /** Token of the card the transaction was made on */ - fun cardToken(cardToken: String) = cardToken(JsonField.of(cardToken)) + /** + * Returns the raw JSON value of [token]. + * + * Unlike [token], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("token") @ExcludeMissing fun _token(): JsonField = token /** - * Sets [Builder.cardToken] to an arbitrary JSON value. + * Returns the raw JSON value of [accountToken]. * - * You should usually call [Builder.cardToken] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. + * Unlike [accountToken], this method doesn't throw if the JSON field has an unexpected + * type. */ - fun cardToken(cardToken: JsonField) = apply { this.cardToken = cardToken } + @JsonProperty("account_token") + @ExcludeMissing + fun _accountToken(): JsonField = accountToken - /** Date and time at which the transaction was created */ - fun transactionCreatedAt(transactionCreatedAt: OffsetDateTime) = - transactionCreatedAt(JsonField.of(transactionCreatedAt)) + /** + * Returns the raw JSON value of [addedAt]. + * + * Unlike [addedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("added_at") + @ExcludeMissing + fun _addedAt(): JsonField = addedAt /** - * Sets [Builder.transactionCreatedAt] to an arbitrary JSON value. + * Returns the raw JSON value of [cardToken]. * - * You should usually call [Builder.transactionCreatedAt] with a well-typed [OffsetDateTime] - * value instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. + * Unlike [cardToken], this method doesn't throw if the JSON field has an unexpected type. */ - fun transactionCreatedAt(transactionCreatedAt: JsonField) = apply { - this.transactionCreatedAt = transactionCreatedAt - } + @JsonProperty("card_token") @ExcludeMissing fun _cardToken(): JsonField = cardToken - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** + * Returns the raw JSON value of [category]. + * + * Unlike [category], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("category") @ExcludeMissing fun _category(): JsonField = category + + /** + * Returns the raw JSON value of [transactionCreatedAt]. + * + * Unlike [transactionCreatedAt], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("transaction_created_at") + @ExcludeMissing + fun _transactionCreatedAt(): JsonField = transactionCreatedAt - 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) + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [CardCaseTransaction]. + * + * The following fields are required: + * ```java + * .token() + * .accountToken() + * .addedAt() + * .cardToken() + * .category() + * .transactionCreatedAt() + * ``` + */ + @JvmStatic fun builder() = Builder() } - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + /** A builder for [CardCaseTransaction]. */ + class Builder internal constructor() { + + private var token: JsonField? = null + private var accountToken: JsonField? = null + private var addedAt: JsonField? = null + private var cardToken: JsonField? = null + private var category: JsonField? = null + private var transactionCreatedAt: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(cardCaseTransaction: CardCaseTransaction) = apply { + token = cardCaseTransaction.token + accountToken = cardCaseTransaction.accountToken + addedAt = cardCaseTransaction.addedAt + cardToken = cardCaseTransaction.cardToken + category = cardCaseTransaction.category + transactionCreatedAt = cardCaseTransaction.transactionCreatedAt + additionalProperties = cardCaseTransaction.additionalProperties.toMutableMap() + } + + /** Globally unique identifier for the card transaction */ + fun token(token: String) = token(JsonField.of(token)) + + /** + * Sets [Builder.token] to an arbitrary JSON value. + * + * You should usually call [Builder.token] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun token(token: JsonField) = apply { this.token = token } + + /** Token of the account the transaction belongs to */ + fun accountToken(accountToken: String) = accountToken(JsonField.of(accountToken)) + + /** + * Sets [Builder.accountToken] to an arbitrary JSON value. + * + * You should usually call [Builder.accountToken] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun accountToken(accountToken: JsonField) = apply { + this.accountToken = accountToken + } + + /** Date and time at which the transaction was added to the case */ + fun addedAt(addedAt: OffsetDateTime) = addedAt(JsonField.of(addedAt)) + + /** + * Sets [Builder.addedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.addedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun addedAt(addedAt: JsonField) = apply { this.addedAt = addedAt } + + /** Token of the card the transaction was made on */ + fun cardToken(cardToken: String) = cardToken(JsonField.of(cardToken)) + + /** + * Sets [Builder.cardToken] to an arbitrary JSON value. + * + * You should usually call [Builder.cardToken] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun cardToken(cardToken: JsonField) = apply { this.cardToken = cardToken } - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) + fun category(category: Category) = category(JsonField.of(category)) + + /** + * Sets [Builder.category] to an arbitrary JSON value. + * + * You should usually call [Builder.category] with a well-typed [Category] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun category(category: JsonField) = apply { this.category = category } + + /** Date and time at which the transaction was created */ + fun transactionCreatedAt(transactionCreatedAt: OffsetDateTime) = + transactionCreatedAt(JsonField.of(transactionCreatedAt)) + + /** + * Sets [Builder.transactionCreatedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.transactionCreatedAt] with a well-typed + * [OffsetDateTime] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun transactionCreatedAt(transactionCreatedAt: JsonField) = apply { + this.transactionCreatedAt = transactionCreatedAt + } + + 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 [CardCaseTransaction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .token() + * .accountToken() + * .addedAt() + * .cardToken() + * .category() + * .transactionCreatedAt() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): CardCaseTransaction = + CardCaseTransaction( + checkRequired("token", token), + checkRequired("accountToken", accountToken), + checkRequired("addedAt", addedAt), + checkRequired("cardToken", cardToken), + checkRequired("category", category), + checkRequired("transactionCreatedAt", transactionCreatedAt), + additionalProperties.toMutableMap(), + ) } + private var validated: Boolean = false + /** - * Returns an immutable instance of [CaseTransaction]. + * Validates that the types of all values in this object match their expected types + * recursively. * - * Further updates to this [Builder] will not mutate the returned instance. + * This method is _not_ forwards compatible with new types from the API for existing fields. * - * The following fields are required: - * ```java - * .token() - * .accountToken() - * .addedAt() - * .cardToken() - * .transactionCreatedAt() - * ``` + * @throws LithicInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): CardCaseTransaction = apply { + if (validated) { + return@apply + } + + token() + accountToken() + addedAt() + cardToken() + category().validate() + transactionCreatedAt() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: LithicInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. * - * @throws IllegalStateException if any required field is unset. + * Used for best match union deserialization. */ - fun build(): CaseTransaction = - CaseTransaction( - checkRequired("token", token), - checkRequired("accountToken", accountToken), - checkRequired("addedAt", addedAt), - checkRequired("cardToken", cardToken), - checkRequired("transactionCreatedAt", transactionCreatedAt), - additionalProperties.toMutableMap(), - ) - } + @JvmSynthetic + internal fun validity(): Int = + (if (token.asKnown().isPresent) 1 else 0) + + (if (accountToken.asKnown().isPresent) 1 else 0) + + (if (addedAt.asKnown().isPresent) 1 else 0) + + (if (cardToken.asKnown().isPresent) 1 else 0) + + (category.asKnown().getOrNull()?.validity() ?: 0) + + (if (transactionCreatedAt.asKnown().isPresent) 1 else 0) - private var validated: Boolean = false + class Category @JsonCreator private constructor(private val value: JsonField) : + Enum { - /** - * Validates that the types of all values in this object match their expected types recursively. - * - * This method is _not_ forwards compatible with new types from the API for existing fields. - * - * @throws LithicInvalidDataException if any value type in this object doesn't match its - * expected type. - */ - fun validate(): CaseTransaction = apply { - if (validated) { - return@apply - } + /** + * 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 - token() - accountToken() - addedAt() - cardToken() - transactionCreatedAt() - validated = true - } + companion object { - fun isValid(): Boolean = - try { - validate() - true - } catch (e: LithicInvalidDataException) { - false + @JvmField val CARD = of("CARD") + + @JvmStatic fun of(value: String) = Category(JsonField.of(value)) + } + + /** An enum containing [Category]'s known values. */ + enum class Known { + CARD + } + + /** + * An enum containing [Category]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Category] 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 { + CARD, + /** + * An enum member indicating that [Category] 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) { + CARD -> Value.CARD + 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 LithicInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + CARD -> Known.CARD + else -> throw LithicInvalidDataException("Unknown Category: $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 LithicInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + LithicInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws LithicInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): Category = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: LithicInvalidDataException) { + 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 Category && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } - /** - * 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 (token.asKnown().isPresent) 1 else 0) + - (if (accountToken.asKnown().isPresent) 1 else 0) + - (if (addedAt.asKnown().isPresent) 1 else 0) + - (if (cardToken.asKnown().isPresent) 1 else 0) + - (if (transactionCreatedAt.asKnown().isPresent) 1 else 0) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + return other is CardCaseTransaction && + token == other.token && + accountToken == other.accountToken && + addedAt == other.addedAt && + cardToken == other.cardToken && + category == other.category && + transactionCreatedAt == other.transactionCreatedAt && + additionalProperties == other.additionalProperties } - return other is CaseTransaction && - token == other.token && - accountToken == other.accountToken && - addedAt == other.addedAt && - cardToken == other.cardToken && - transactionCreatedAt == other.transactionCreatedAt && - additionalProperties == other.additionalProperties + private val hashCode: Int by lazy { + Objects.hash( + token, + accountToken, + addedAt, + cardToken, + category, + transactionCreatedAt, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "CardCaseTransaction{token=$token, accountToken=$accountToken, addedAt=$addedAt, cardToken=$cardToken, category=$category, transactionCreatedAt=$transactionCreatedAt, additionalProperties=$additionalProperties}" } - private val hashCode: Int by lazy { - Objects.hash( + /** A payment (ACH) transaction associated with a case */ + class PaymentCaseTransaction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val token: JsonField, + private val addedAt: JsonField, + private val category: JsonField, + private val financialAccountToken: JsonField, + private val transactionCreatedAt: JsonField, + private val accountToken: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("token") @ExcludeMissing token: JsonField = JsonMissing.of(), + @JsonProperty("added_at") + @ExcludeMissing + addedAt: JsonField = JsonMissing.of(), + @JsonProperty("category") + @ExcludeMissing + category: JsonField = JsonMissing.of(), + @JsonProperty("financial_account_token") + @ExcludeMissing + financialAccountToken: JsonField = JsonMissing.of(), + @JsonProperty("transaction_created_at") + @ExcludeMissing + transactionCreatedAt: JsonField = JsonMissing.of(), + @JsonProperty("account_token") + @ExcludeMissing + accountToken: JsonField = JsonMissing.of(), + ) : this( token, - accountToken, addedAt, - cardToken, + category, + financialAccountToken, transactionCreatedAt, - additionalProperties, + accountToken, + mutableMapOf(), ) - } - override fun hashCode(): Int = hashCode + /** + * Globally unique identifier for the payment transaction + * + * @throws LithicInvalidDataException 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 token(): String = token.getRequired("token") + + /** + * Date and time at which the transaction was added to the case + * + * @throws LithicInvalidDataException 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 addedAt(): OffsetDateTime = addedAt.getRequired("added_at") + + /** + * @throws LithicInvalidDataException 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 category(): Category = category.getRequired("category") + + /** + * Token of the financial account the payment belongs to + * + * @throws LithicInvalidDataException 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 financialAccountToken(): String = + financialAccountToken.getRequired("financial_account_token") + + /** + * Date and time at which the transaction was created + * + * @throws LithicInvalidDataException 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 transactionCreatedAt(): OffsetDateTime = + transactionCreatedAt.getRequired("transaction_created_at") + + /** + * Token of the account the payment belongs to, if applicable + * + * @throws LithicInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun accountToken(): Optional = accountToken.getOptional("account_token") + + /** + * Returns the raw JSON value of [token]. + * + * Unlike [token], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("token") @ExcludeMissing fun _token(): JsonField = token + + /** + * Returns the raw JSON value of [addedAt]. + * + * Unlike [addedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("added_at") + @ExcludeMissing + fun _addedAt(): JsonField = addedAt + + /** + * Returns the raw JSON value of [category]. + * + * Unlike [category], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("category") @ExcludeMissing fun _category(): JsonField = category + + /** + * Returns the raw JSON value of [financialAccountToken]. + * + * Unlike [financialAccountToken], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("financial_account_token") + @ExcludeMissing + fun _financialAccountToken(): JsonField = financialAccountToken + + /** + * Returns the raw JSON value of [transactionCreatedAt]. + * + * Unlike [transactionCreatedAt], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("transaction_created_at") + @ExcludeMissing + fun _transactionCreatedAt(): JsonField = transactionCreatedAt + + /** + * Returns the raw JSON value of [accountToken]. + * + * Unlike [accountToken], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("account_token") + @ExcludeMissing + fun _accountToken(): JsonField = accountToken + + @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 [PaymentCaseTransaction]. + * + * The following fields are required: + * ```java + * .token() + * .addedAt() + * .category() + * .financialAccountToken() + * .transactionCreatedAt() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PaymentCaseTransaction]. */ + class Builder internal constructor() { + + private var token: JsonField? = null + private var addedAt: JsonField? = null + private var category: JsonField? = null + private var financialAccountToken: JsonField? = null + private var transactionCreatedAt: JsonField? = null + private var accountToken: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(paymentCaseTransaction: PaymentCaseTransaction) = apply { + token = paymentCaseTransaction.token + addedAt = paymentCaseTransaction.addedAt + category = paymentCaseTransaction.category + financialAccountToken = paymentCaseTransaction.financialAccountToken + transactionCreatedAt = paymentCaseTransaction.transactionCreatedAt + accountToken = paymentCaseTransaction.accountToken + additionalProperties = paymentCaseTransaction.additionalProperties.toMutableMap() + } + + /** Globally unique identifier for the payment transaction */ + fun token(token: String) = token(JsonField.of(token)) + + /** + * Sets [Builder.token] to an arbitrary JSON value. + * + * You should usually call [Builder.token] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun token(token: JsonField) = apply { this.token = token } + + /** Date and time at which the transaction was added to the case */ + fun addedAt(addedAt: OffsetDateTime) = addedAt(JsonField.of(addedAt)) + + /** + * Sets [Builder.addedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.addedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun addedAt(addedAt: JsonField) = apply { this.addedAt = addedAt } + + fun category(category: Category) = category(JsonField.of(category)) + + /** + * Sets [Builder.category] to an arbitrary JSON value. + * + * You should usually call [Builder.category] with a well-typed [Category] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun category(category: JsonField) = apply { this.category = category } + + /** Token of the financial account the payment belongs to */ + fun financialAccountToken(financialAccountToken: String) = + financialAccountToken(JsonField.of(financialAccountToken)) + + /** + * Sets [Builder.financialAccountToken] to an arbitrary JSON value. + * + * You should usually call [Builder.financialAccountToken] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun financialAccountToken(financialAccountToken: JsonField) = apply { + this.financialAccountToken = financialAccountToken + } + + /** Date and time at which the transaction was created */ + fun transactionCreatedAt(transactionCreatedAt: OffsetDateTime) = + transactionCreatedAt(JsonField.of(transactionCreatedAt)) + + /** + * Sets [Builder.transactionCreatedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.transactionCreatedAt] with a well-typed + * [OffsetDateTime] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun transactionCreatedAt(transactionCreatedAt: JsonField) = apply { + this.transactionCreatedAt = transactionCreatedAt + } + + /** Token of the account the payment belongs to, if applicable */ + fun accountToken(accountToken: String) = accountToken(JsonField.of(accountToken)) + + /** + * Sets [Builder.accountToken] to an arbitrary JSON value. + * + * You should usually call [Builder.accountToken] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun accountToken(accountToken: JsonField) = apply { + this.accountToken = accountToken + } + + 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 [PaymentCaseTransaction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .token() + * .addedAt() + * .category() + * .financialAccountToken() + * .transactionCreatedAt() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PaymentCaseTransaction = + PaymentCaseTransaction( + checkRequired("token", token), + checkRequired("addedAt", addedAt), + checkRequired("category", category), + checkRequired("financialAccountToken", financialAccountToken), + checkRequired("transactionCreatedAt", transactionCreatedAt), + accountToken, + additionalProperties.toMutableMap(), + ) + } - override fun toString() = - "CaseTransaction{token=$token, accountToken=$accountToken, addedAt=$addedAt, cardToken=$cardToken, transactionCreatedAt=$transactionCreatedAt, additionalProperties=$additionalProperties}" + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws LithicInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): PaymentCaseTransaction = apply { + if (validated) { + return@apply + } + + token() + addedAt() + category().validate() + financialAccountToken() + transactionCreatedAt() + accountToken() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: LithicInvalidDataException) { + 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 (token.asKnown().isPresent) 1 else 0) + + (if (addedAt.asKnown().isPresent) 1 else 0) + + (category.asKnown().getOrNull()?.validity() ?: 0) + + (if (financialAccountToken.asKnown().isPresent) 1 else 0) + + (if (transactionCreatedAt.asKnown().isPresent) 1 else 0) + + (if (accountToken.asKnown().isPresent) 1 else 0) + + class Category @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 PAYMENT = of("PAYMENT") + + @JvmStatic fun of(value: String) = Category(JsonField.of(value)) + } + + /** An enum containing [Category]'s known values. */ + enum class Known { + PAYMENT + } + + /** + * An enum containing [Category]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Category] 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 { + PAYMENT, + /** + * An enum member indicating that [Category] 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) { + PAYMENT -> Value.PAYMENT + 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 LithicInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + PAYMENT -> Known.PAYMENT + else -> throw LithicInvalidDataException("Unknown Category: $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 LithicInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + LithicInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws LithicInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): Category = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: LithicInvalidDataException) { + 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 Category && 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 PaymentCaseTransaction && + token == other.token && + addedAt == other.addedAt && + category == other.category && + financialAccountToken == other.financialAccountToken && + transactionCreatedAt == other.transactionCreatedAt && + accountToken == other.accountToken && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + token, + addedAt, + category, + financialAccountToken, + transactionCreatedAt, + accountToken, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PaymentCaseTransaction{token=$token, addedAt=$addedAt, category=$category, financialAccountToken=$financialAccountToken, transactionCreatedAt=$transactionCreatedAt, accountToken=$accountToken, additionalProperties=$additionalProperties}" + } } diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPage.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPage.kt index 917362ce9..029b163d1 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPage.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPage.kt @@ -41,9 +41,43 @@ private constructor( fun nextPageParams(): TransactionMonitoringCaseListTransactionsParams = if (params.endingBefore().isPresent) { - params.toBuilder().endingBefore(items().first()._token().getOptional("token")).build() + params + .toBuilder() + .endingBefore( + items() + .first() + .accept( + object : CaseTransaction.Visitor> { + override fun visitCard( + card: CaseTransaction.CardCaseTransaction + ): Optional = card._token().getOptional("token") + + override fun visitPayment( + payment: CaseTransaction.PaymentCaseTransaction + ): Optional = payment._token().getOptional("token") + } + ) + ) + .build() } else { - params.toBuilder().startingAfter(items().last()._token().getOptional("token")).build() + params + .toBuilder() + .startingAfter( + items() + .last() + .accept( + object : CaseTransaction.Visitor> { + override fun visitCard( + card: CaseTransaction.CardCaseTransaction + ): Optional = card._token().getOptional("token") + + override fun visitPayment( + payment: CaseTransaction.PaymentCaseTransaction + ): Optional = payment._token().getOptional("token") + } + ) + ) + .build() } override fun nextPage(): TransactionMonitoringCaseListTransactionsPage = diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageAsync.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageAsync.kt index 20e428043..7655ffdf8 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageAsync.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageAsync.kt @@ -44,9 +44,43 @@ private constructor( fun nextPageParams(): TransactionMonitoringCaseListTransactionsParams = if (params.endingBefore().isPresent) { - params.toBuilder().endingBefore(items().first()._token().getOptional("token")).build() + params + .toBuilder() + .endingBefore( + items() + .first() + .accept( + object : CaseTransaction.Visitor> { + override fun visitCard( + card: CaseTransaction.CardCaseTransaction + ): Optional = card._token().getOptional("token") + + override fun visitPayment( + payment: CaseTransaction.PaymentCaseTransaction + ): Optional = payment._token().getOptional("token") + } + ) + ) + .build() } else { - params.toBuilder().startingAfter(items().last()._token().getOptional("token")).build() + params + .toBuilder() + .startingAfter( + items() + .last() + .accept( + object : CaseTransaction.Visitor> { + override fun visitCard( + card: CaseTransaction.CardCaseTransaction + ): Optional = card._token().getOptional("token") + + override fun visitPayment( + payment: CaseTransaction.PaymentCaseTransaction + ): Optional = payment._token().getOptional("token") + } + ) + ) + .build() } override fun nextPage(): CompletableFuture = diff --git a/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageResponse.kt b/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageResponse.kt index e5d9126e3..3bf6022c1 100644 --- a/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageResponse.kt +++ b/lithic-java-core/src/main/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageResponse.kt @@ -134,6 +134,14 @@ private constructor( } } + /** Alias for calling [addData] with `CaseTransaction.ofCard(card)`. */ + fun addData(card: CaseTransaction.CardCaseTransaction) = + addData(CaseTransaction.ofCard(card)) + + /** Alias for calling [addData] with `CaseTransaction.ofPayment(payment)`. */ + fun addData(payment: CaseTransaction.PaymentCaseTransaction) = + addData(CaseTransaction.ofPayment(payment)) + fun hasMore(hasMore: Boolean) = hasMore(JsonField.of(hasMore)) /** diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/CaseTransactionTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/CaseTransactionTest.kt index c0d8e2ebb..5613dce7a 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/CaseTransactionTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/CaseTransactionTest.kt @@ -3,45 +3,93 @@ package com.lithic.api.models import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.lithic.api.core.JsonValue import com.lithic.api.core.jsonMapper +import com.lithic.api.errors.LithicInvalidDataException import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource internal class CaseTransactionTest { @Test - fun create() { - val caseTransaction = - CaseTransaction.builder() + fun ofCard() { + val card = + CaseTransaction.CardCaseTransaction.builder() .token("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .addedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .cardToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .category(CaseTransaction.CardCaseTransaction.Category.CARD) .transactionCreatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .build() - assertThat(caseTransaction.token()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(caseTransaction.accountToken()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(caseTransaction.addedAt()) - .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - assertThat(caseTransaction.cardToken()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(caseTransaction.transactionCreatedAt()) - .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + val caseTransaction = CaseTransaction.ofCard(card) + + assertThat(caseTransaction.card()).contains(card) + assertThat(caseTransaction.payment()).isEmpty } @Test - fun roundtrip() { + fun ofCardRoundtrip() { val jsonMapper = jsonMapper() val caseTransaction = - CaseTransaction.builder() + CaseTransaction.ofCard( + CaseTransaction.CardCaseTransaction.builder() + .token("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .cardToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .category(CaseTransaction.CardCaseTransaction.Category.CARD) + .transactionCreatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .build() + ) + + val roundtrippedCaseTransaction = + jsonMapper.readValue( + jsonMapper.writeValueAsString(caseTransaction), + jacksonTypeRef(), + ) + + assertThat(roundtrippedCaseTransaction).isEqualTo(caseTransaction) + } + + @Test + fun ofPayment() { + val payment = + CaseTransaction.PaymentCaseTransaction.builder() .token("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .addedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .cardToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .category(CaseTransaction.PaymentCaseTransaction.Category.PAYMENT) + .financialAccountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .transactionCreatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() + val caseTransaction = CaseTransaction.ofPayment(payment) + + assertThat(caseTransaction.card()).isEmpty + assertThat(caseTransaction.payment()).contains(payment) + } + + @Test + fun ofPaymentRoundtrip() { + val jsonMapper = jsonMapper() + val caseTransaction = + CaseTransaction.ofPayment( + CaseTransaction.PaymentCaseTransaction.builder() + .token("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .category(CaseTransaction.PaymentCaseTransaction.Category.PAYMENT) + .financialAccountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .transactionCreatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + val roundtrippedCaseTransaction = jsonMapper.readValue( jsonMapper.writeValueAsString(caseTransaction), @@ -50,4 +98,22 @@ internal class CaseTransactionTest { assertThat(roundtrippedCaseTransaction).isEqualTo(caseTransaction) } + + enum class IncompatibleJsonShapeTestCase(val value: JsonValue) { + BOOLEAN(JsonValue.from(false)), + STRING(JsonValue.from("invalid")), + INTEGER(JsonValue.from(-1)), + FLOAT(JsonValue.from(3.14)), + ARRAY(JsonValue.from(listOf("invalid", "array"))), + } + + @ParameterizedTest + @EnumSource + fun incompatibleJsonShapeDeserializesToUnknown(testCase: IncompatibleJsonShapeTestCase) { + val caseTransaction = + jsonMapper().convertValue(testCase.value, jacksonTypeRef()) + + val e = assertThrows { caseTransaction.validate() } + assertThat(e).hasMessageStartingWith("Unknown ") + } } diff --git a/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageResponseTest.kt b/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageResponseTest.kt index 037cd350b..92ac7c165 100644 --- a/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageResponseTest.kt +++ b/lithic-java-core/src/test/kotlin/com/lithic/api/models/TransactionMonitoringCaseListTransactionsPageResponseTest.kt @@ -15,11 +15,12 @@ internal class TransactionMonitoringCaseListTransactionsPageResponseTest { val transactionMonitoringCaseListTransactionsPageResponse = TransactionMonitoringCaseListTransactionsPageResponse.builder() .addData( - CaseTransaction.builder() + CaseTransaction.CardCaseTransaction.builder() .token("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .addedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .cardToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .category(CaseTransaction.CardCaseTransaction.Category.CARD) .transactionCreatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .build() ) @@ -28,13 +29,16 @@ internal class TransactionMonitoringCaseListTransactionsPageResponseTest { assertThat(transactionMonitoringCaseListTransactionsPageResponse.data()) .containsExactly( - CaseTransaction.builder() - .token("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .addedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .cardToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .transactionCreatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .build() + CaseTransaction.ofCard( + CaseTransaction.CardCaseTransaction.builder() + .token("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .cardToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .category(CaseTransaction.CardCaseTransaction.Category.CARD) + .transactionCreatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .build() + ) ) assertThat(transactionMonitoringCaseListTransactionsPageResponse.hasMore()).isEqualTo(true) } @@ -45,11 +49,12 @@ internal class TransactionMonitoringCaseListTransactionsPageResponseTest { val transactionMonitoringCaseListTransactionsPageResponse = TransactionMonitoringCaseListTransactionsPageResponse.builder() .addData( - CaseTransaction.builder() + CaseTransaction.CardCaseTransaction.builder() .token("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .addedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .cardToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .category(CaseTransaction.CardCaseTransaction.Category.CARD) .transactionCreatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .build() ) From 348562d551a31261b2f577215ee2466f45322d0a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 12:34:24 +0000 Subject: [PATCH 3/3] release: 0.131.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ README.md | 10 +++++----- build.gradle.kts | 2 +- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 37e997234..a24ae611f 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.130.0" + ".": "0.131.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 88d1519c2..98d31de2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 0.131.0 (2026-06-29) + +Full Changelog: [v0.130.0...v0.131.0](https://github.com/lithic-com/lithic-java/compare/v0.130.0...v0.131.0) + +### Features + +* **types:** convert CaseTransaction to union with card/payment variants ([97a5e53](https://github.com/lithic-com/lithic-java/commit/97a5e536cd0656291804ebda8b21d67ada4a1baf)) + + +### Documentation + +* **types:** clarify cash_amount description in CardAuthorization models ([900a6b2](https://github.com/lithic-com/lithic-java/commit/900a6b205597d95620df418d01cd5cf43ccbaa04)) + ## 0.130.0 (2026-06-23) Full Changelog: [v0.129.0...v0.130.0](https://github.com/lithic-com/lithic-java/compare/v0.129.0...v0.130.0) diff --git a/README.md b/README.md index 4aedcced5..2a94f696a 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.lithic.api/lithic-java)](https://central.sonatype.com/artifact/com.lithic.api/lithic-java/0.130.0) -[![javadoc](https://javadoc.io/badge2/com.lithic.api/lithic-java/0.130.0/javadoc.svg)](https://javadoc.io/doc/com.lithic.api/lithic-java/0.130.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.lithic.api/lithic-java)](https://central.sonatype.com/artifact/com.lithic.api/lithic-java/0.131.0) +[![javadoc](https://javadoc.io/badge2/com.lithic.api/lithic-java/0.131.0/javadoc.svg)](https://javadoc.io/doc/com.lithic.api/lithic-java/0.131.0) @@ -22,7 +22,7 @@ Use the Lithic MCP Server to enable AI assistants to interact with this API, all -The REST API documentation can be found on [docs.lithic.com](https://docs.lithic.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.lithic.api/lithic-java/0.130.0). +The REST API documentation can be found on [docs.lithic.com](https://docs.lithic.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.lithic.api/lithic-java/0.131.0). @@ -33,7 +33,7 @@ The REST API documentation can be found on [docs.lithic.com](https://docs.lithic ### Gradle ```kotlin -implementation("com.lithic.api:lithic-java:0.130.0") +implementation("com.lithic.api:lithic-java:0.131.0") ``` ### Maven @@ -42,7 +42,7 @@ implementation("com.lithic.api:lithic-java:0.130.0") com.lithic.api lithic-java - 0.130.0 + 0.131.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index 32e805ce5..2bed69f41 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { allprojects { group = "com.lithic.api" - version = "0.130.0" // x-release-please-version + version = "0.131.0" // x-release-please-version } subprojects {