diff --git a/pom.xml b/pom.xml index c7ad738..55a6f5c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ ai.pluggy pluggy-java - 1.10.0 + 1.11.0 jar @@ -86,6 +86,24 @@ + + + + src/main/resources + true + + pluggy.properties + + + + src/main/resources + false + + pluggy.properties + + + diff --git a/src/main/java/ai/pluggy/client/PluggyClient.java b/src/main/java/ai/pluggy/client/PluggyClient.java index eda479c..f46227e 100644 --- a/src/main/java/ai/pluggy/client/PluggyClient.java +++ b/src/main/java/ai/pluggy/client/PluggyClient.java @@ -9,6 +9,7 @@ import ai.pluggy.client.response.ErrorResponse; import ai.pluggy.exception.PluggyException; import ai.pluggy.utils.Utils; +import ai.pluggy.utils.Version; import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -292,7 +293,7 @@ public String authenticate() throws IOException, PluggyException { .post(body) .addHeader("content-type", "application/json") .addHeader("cache-control", "no-cache") - .addHeader("User-Agent", "PluggyJava/0.16.2") + .addHeader("User-Agent", Version.userAgent()) .build(); String apiKey; diff --git a/src/main/java/ai/pluggy/client/auth/ApiKeyAuthInterceptor.java b/src/main/java/ai/pluggy/client/auth/ApiKeyAuthInterceptor.java index fff3926..fe2af9b 100644 --- a/src/main/java/ai/pluggy/client/auth/ApiKeyAuthInterceptor.java +++ b/src/main/java/ai/pluggy/client/auth/ApiKeyAuthInterceptor.java @@ -2,6 +2,7 @@ import static ai.pluggy.utils.Asserts.assertNotNull; +import ai.pluggy.utils.Version; import com.google.gson.Gson; import java.io.IOException; @@ -114,8 +115,7 @@ private Request requestWithAuth(Request originalRequest, String apiKey) { // override the apiKey of the original request with the new one return originalRequest.newBuilder() .header(X_API_KEY_HEADER, apiKey) - // TOOD: add dynamic version - .header("User-Agent", "PluggyJava/0.16.2") + .header("User-Agent", Version.userAgent()) .build(); } diff --git a/src/main/java/ai/pluggy/client/response/CreditCardAccountFeeType.java b/src/main/java/ai/pluggy/client/response/CreditCardAccountFeeType.java new file mode 100644 index 0000000..4d449a2 --- /dev/null +++ b/src/main/java/ai/pluggy/client/response/CreditCardAccountFeeType.java @@ -0,0 +1,28 @@ +package ai.pluggy.client.response; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +public enum CreditCardAccountFeeType { + @SerializedName("ANNUAL_FEE") + ANNUAL_FEE("ANNUAL_FEE"), + @SerializedName("ATM_WITHDRAWAL_DOMESTIC") + ATM_WITHDRAWAL_DOMESTIC("ATM_WITHDRAWAL_DOMESTIC"), + @SerializedName("ATM_WITHDRAWAL_INTERNATIONAL") + ATM_WITHDRAWAL_INTERNATIONAL("ATM_WITHDRAWAL_INTERNATIONAL"), + @SerializedName("EMERGENCY_CREDIT_EVALUATION") + EMERGENCY_CREDIT_EVALUATION("EMERGENCY_CREDIT_EVALUATION"), + @SerializedName("CARD_REISSUE") + CARD_REISSUE("CARD_REISSUE"), + @SerializedName("BILL_PAYMENT_FEE") + BILL_PAYMENT_FEE("BILL_PAYMENT_FEE"), + @SerializedName("SMS") + SMS("SMS"), + @SerializedName("OTHER") + OTHER("OTHER"); + + @Getter + private String value; +} diff --git a/src/main/java/ai/pluggy/client/response/CreditCardAccountOtherCreditType.java b/src/main/java/ai/pluggy/client/response/CreditCardAccountOtherCreditType.java new file mode 100644 index 0000000..7ff49b1 --- /dev/null +++ b/src/main/java/ai/pluggy/client/response/CreditCardAccountOtherCreditType.java @@ -0,0 +1,20 @@ +package ai.pluggy.client.response; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +public enum CreditCardAccountOtherCreditType { + @SerializedName("REVOLVING_CREDIT") + REVOLVING_CREDIT("REVOLVING_CREDIT"), + @SerializedName("BILL_INSTALLMENT") + BILL_INSTALLMENT("BILL_INSTALLMENT"), + @SerializedName("LOAN") + LOAN("LOAN"), + @SerializedName("OTHER") + OTHER("OTHER"); + + @Getter + private String value; +} diff --git a/src/main/java/ai/pluggy/client/response/CreditCardLimitLineName.java b/src/main/java/ai/pluggy/client/response/CreditCardLimitLineName.java new file mode 100644 index 0000000..2dd7c97 --- /dev/null +++ b/src/main/java/ai/pluggy/client/response/CreditCardLimitLineName.java @@ -0,0 +1,24 @@ +package ai.pluggy.client.response; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +public enum CreditCardLimitLineName { + @SerializedName("CREDITO_A_VISTA") + CREDITO_A_VISTA("CREDITO_A_VISTA"), + @SerializedName("CREDITO_PARCELADO") + CREDITO_PARCELADO("CREDITO_PARCELADO"), + @SerializedName("SAQUE_CREDITO_BRASIL") + SAQUE_CREDITO_BRASIL("SAQUE_CREDITO_BRASIL"), + @SerializedName("SAQUE_CREDITO_EXTERIOR") + SAQUE_CREDITO_EXTERIOR("SAQUE_CREDITO_EXTERIOR"), + @SerializedName("EMPRESTIMO_CARTAO_CONSIGNADO") + EMPRESTIMO_CARTAO_CONSIGNADO("EMPRESTIMO_CARTAO_CONSIGNADO"), + @SerializedName("OUTROS") + OUTROS("OUTROS"); + + @Getter + private String value; +} diff --git a/src/main/java/ai/pluggy/client/response/CreditData.java b/src/main/java/ai/pluggy/client/response/CreditData.java index cd33570..4168fa9 100644 --- a/src/main/java/ai/pluggy/client/response/CreditData.java +++ b/src/main/java/ai/pluggy/client/response/CreditData.java @@ -3,12 +3,15 @@ import lombok.Builder; import lombok.Data; +import java.util.List; + @Data @Builder public class CreditData { String level; String brand; + String brandAdditionalInfo; String balanceCloseDate; String balanceDueDate; Double availableCreditLimit; @@ -17,4 +20,5 @@ public class CreditData { Double creditLimit; HolderType holderType; CreditCardStatus status; + List disaggregatedCreditLimits; } diff --git a/src/main/java/ai/pluggy/client/response/DisaggregatedCreditLimit.java b/src/main/java/ai/pluggy/client/response/DisaggregatedCreditLimit.java new file mode 100644 index 0000000..5c0cb41 --- /dev/null +++ b/src/main/java/ai/pluggy/client/response/DisaggregatedCreditLimit.java @@ -0,0 +1,14 @@ +package ai.pluggy.client.response; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class DisaggregatedCreditLimit { + + CreditCardLimitLineName lineName; + String limitAmountReason; + Double customizedLimitAmount; + String customizedLimitAmountCurrencyCode; +} diff --git a/src/main/java/ai/pluggy/client/response/TransactionCreditCardMetadata.java b/src/main/java/ai/pluggy/client/response/TransactionCreditCardMetadata.java index d5abeea..580ea0a 100644 --- a/src/main/java/ai/pluggy/client/response/TransactionCreditCardMetadata.java +++ b/src/main/java/ai/pluggy/client/response/TransactionCreditCardMetadata.java @@ -13,4 +13,8 @@ public class TransactionCreditCardMetadata { Date purchaseDate; String cardNumber; String billId; + CreditCardAccountFeeType feeType; + String feeTypeAdditionalInfo; + CreditCardAccountOtherCreditType otherCreditsType; + String otherCreditsAdditionalInfo; } diff --git a/src/main/java/ai/pluggy/utils/Version.java b/src/main/java/ai/pluggy/utils/Version.java new file mode 100644 index 0000000..fb0f35e --- /dev/null +++ b/src/main/java/ai/pluggy/utils/Version.java @@ -0,0 +1,46 @@ +package ai.pluggy.utils; + +import java.io.InputStream; +import java.util.Properties; + +/** + * Exposes the SDK version, derived from the Maven {@code project.version} at build time via + * resource filtering of {@code pluggy.properties}. Used to build the {@code User-Agent} header so it + * stays in sync with {@code pom.xml} automatically. + */ +public final class Version { + + private static final String UNKNOWN = "unknown"; + private static final String VERSION = load(); + + private Version() { + } + + /** SDK version (e.g. {@code "1.11.0"}), or {@code "unknown"} if it can't be resolved. */ + public static String get() { + return VERSION; + } + + /** {@code User-Agent} header value, e.g. {@code "PluggyJava/1.11.0"}. */ + public static String userAgent() { + return "PluggyJava/" + VERSION; + } + + private static String load() { + try (InputStream in = Version.class.getResourceAsStream("/pluggy.properties")) { + if (in == null) { + return UNKNOWN; + } + Properties props = new Properties(); + props.load(in); + String version = props.getProperty("version"); + // Guard against an unfiltered placeholder (e.g. if resource filtering didn't run). + if (version == null || version.isEmpty() || version.startsWith("${")) { + return UNKNOWN; + } + return version; + } catch (Exception e) { + return UNKNOWN; + } + } +} diff --git a/src/main/resources/pluggy.properties b/src/main/resources/pluggy.properties new file mode 100644 index 0000000..defbd48 --- /dev/null +++ b/src/main/resources/pluggy.properties @@ -0,0 +1 @@ +version=${project.version} diff --git a/src/test/java/ai/pluggy/utils/VersionTest.java b/src/test/java/ai/pluggy/utils/VersionTest.java new file mode 100644 index 0000000..ee63c63 --- /dev/null +++ b/src/test/java/ai/pluggy/utils/VersionTest.java @@ -0,0 +1,24 @@ +package ai.pluggy.utils; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class VersionTest { + + @Test + public void version_isResolvedFromFilteredProperties() { + // Resource filtering replaces ${project.version} at build time. If the filtering config + // is removed, Version falls back to "unknown" and these assertions fail. + String version = Version.get(); + assertFalse(version.isEmpty(), "version should not be empty"); + assertFalse("unknown".equals(version), "version should resolve from pluggy.properties"); + assertFalse(version.startsWith("${"), "version placeholder should be filtered"); + } + + @Test + public void userAgent_hasExpectedPrefix() { + assertTrue(Version.userAgent().startsWith("PluggyJava/")); + } +}