diff --git a/CHANGELOG.md b/CHANGELOG.md index 66385d5a..7e398a71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### v4.0.2 (2026-01-30) +* * * + +### New Features: +* Add custom field filtering support for list operations using type-safe filters. + ### v4.0.1 (2026-01-19) * * * diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..bd646f56 --- /dev/null +++ b/Makefile @@ -0,0 +1,89 @@ +.PHONY: update-version increment-major increment-minor increment-patch test build clean install check + +# Version file location +VERSION_FILE := VERSION +BUILD_GRADLE_FILE := build.gradle.kts + +# Gradle commands +GRADLE := ./gradlew + +update-version: + @echo "$(VERSION)" > $(VERSION_FILE) + @perl -pi -e 's|version = "[.\-\d\w]+"|version = "$(VERSION)"|' $(BUILD_GRADLE_FILE) + @echo "Updated version to $(VERSION)" + +increment-major: + $(eval CURRENT := $(shell cat $(VERSION_FILE))) + $(eval MAJOR := $(shell echo $(CURRENT) | cut -d. -f1)) + $(eval NEW_VERSION := $(shell echo $$(($(MAJOR) + 1)).0.0)) + @$(MAKE) update-version VERSION=$(NEW_VERSION) + @echo "Version bumped from $(CURRENT) to $(NEW_VERSION)" + +increment-minor: + $(eval CURRENT := $(shell cat $(VERSION_FILE))) + $(eval MAJOR := $(shell echo $(CURRENT) | cut -d. -f1)) + $(eval MINOR := $(shell echo $(CURRENT) | cut -d. -f2)) + $(eval NEW_VERSION := $(MAJOR).$(shell echo $$(($(MINOR) + 1))).0) + @$(MAKE) update-version VERSION=$(NEW_VERSION) + @echo "Version bumped from $(CURRENT) to $(NEW_VERSION)" + +increment-patch: + $(eval CURRENT := $(shell cat $(VERSION_FILE))) + $(eval MAJOR := $(shell echo $(CURRENT) | cut -d. -f1)) + $(eval MINOR := $(shell echo $(CURRENT) | cut -d. -f2)) + $(eval PATCH := $(shell echo $(CURRENT) | cut -d. -f3)) + $(eval NEW_VERSION := $(MAJOR).$(MINOR).$(shell echo $$(($(PATCH) + 1)))) + @$(MAKE) update-version VERSION=$(NEW_VERSION) + @echo "Version bumped from $(CURRENT) to $(NEW_VERSION)" + +install: + @echo "Installing dependencies..." + @$(GRADLE) dependencies + +test: + @echo "Running tests..." + @$(GRADLE) test + +test-coverage: + @echo "Running tests with coverage..." + @$(GRADLE) test jacocoTestReport + @echo "Coverage report generated in build/reports/jacoco/test/html/index.html" + +security-check: + @echo "Running OWASP dependency check..." + @$(GRADLE) dependencyCheckAnalyze + +check: test + @echo "All checks passed!" + +build: clean + @echo "Building project..." + @$(GRADLE) build + +clean: + @echo "Cleaning build artifacts..." + @$(GRADLE) clean + @rm -rf build/ + @rm -rf dist/ + @rm -rf target/ + @find . -type f -name '.DS_Store' -delete + +javadoc: + @echo "Generating Javadoc..." + @$(GRADLE) javadoc + +jar: + @echo "Building JAR..." + @$(GRADLE) jar + +assemble: + @echo "Assembling artifacts..." + @$(GRADLE) assemble + +update: + @echo "Updating dependencies..." + @$(GRADLE) dependencies --refresh-dependencies + +outdated: + @echo "Checking for outdated dependencies..." + @$(GRADLE) dependencyUpdates diff --git a/README.md b/README.md index d79e12f9..8da1f945 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,20 @@ future.thenAccept(resp -> { }); ``` +### Custom Field Filtering + +Filter list operations by custom fields using type-safe filters (`stringFilter()`, `numberFilter()`, `timestampFilter()`, `booleanFilter()`): + +```java +CustomerListParams params = CustomerListParams.builder() + .customField("cf_plan_tier").stringFilter().in("gold", "platinum") + .customField("cf_is_vip").booleanFilter().is(true) + .customField("cf_total_spent").numberFilter().gte(5000L) + .build(); + +CustomerListResponse response = client.customers().list(params); +``` + ### Exception Handling The library provides a comprehensive exception hierarchy with **strongly-typed error enums** to handle different types of errors that may occur during API operations. diff --git a/VERSION b/VERSION new file mode 100644 index 00000000..ee74734a --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +4.1.0 diff --git a/build.gradle.kts b/build.gradle.kts index a1c68d92..7ec634a5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ plugins { } group = "com.chargebee" -version = "4.0.1" +version = "4.1.0" description = "Java client library for ChargeBee" // Project metadata diff --git a/src/main/java/com/chargebee/v4/filters/BooleanFilter.java b/src/main/java/com/chargebee/v4/filters/BooleanFilter.java new file mode 100644 index 00000000..1488ca8a --- /dev/null +++ b/src/main/java/com/chargebee/v4/filters/BooleanFilter.java @@ -0,0 +1,36 @@ +/* + * This file is auto-generated by Chargebee. + * Copyright 2025 Chargebee Inc. + */ + +package com.chargebee.v4.filters; + +import java.util.Map; + +/** + * Filter for boolean fields supporting is, isPresent operations. + * + * @param The builder type to return for method chaining + */ +public class BooleanFilter { + + protected final String fieldName; + protected final B builder; + protected final Map params; + + public BooleanFilter(String fieldName, B builder, Map params) { + this.fieldName = fieldName; + this.builder = builder; + this.params = params; + } + + public B is(Boolean value) { + params.put(fieldName + "[is]", String.valueOf(value)); + return builder; + } + + public B isPresent(boolean value) { + params.put(fieldName + "[is_present]", String.valueOf(value)); + return builder; + } +} diff --git a/src/main/java/com/chargebee/v4/filters/CustomFieldSelector.java b/src/main/java/com/chargebee/v4/filters/CustomFieldSelector.java new file mode 100644 index 00000000..1196ab8d --- /dev/null +++ b/src/main/java/com/chargebee/v4/filters/CustomFieldSelector.java @@ -0,0 +1,71 @@ +/* + * This file is auto-generated by Chargebee. + * Copyright 2025 Chargebee Inc. + */ + +package com.chargebee.v4.filters; + +import java.util.Map; + +/** + * Selector for custom field filters. Allows choosing the appropriate filter type + * (string, number, timestamp, boolean) for a custom field. + * + * @param The builder type to return for method chaining + */ +public class CustomFieldSelector { + + private final String fieldName; + private final B builder; + private final Map params; + + public CustomFieldSelector(String fieldName, B builder, Map params) { + this.fieldName = fieldName; + this.builder = builder; + this.params = params; + } + + /** + * Create a string filter for this custom field. + * Supports is, isNot, startsWith, in, notIn, isPresent operations. + * + * @return StringFilter for the custom field + */ + public StringFilter stringFilter() { + return new StringFilter<>(fieldName, builder, params) + .supportsPresenceOperator(true) + .supportsMultiOperators(true); + } + + /** + * Create a number filter for this custom field. + * Supports is, isNot, lt, lte, gt, gte, between, isPresent operations. + * + * @return NumberFilter for the custom field + */ + public NumberFilter numberFilter() { + return new NumberFilter<>(fieldName, builder, params) + .supportsPresenceOperator(true); + } + + /** + * Create a timestamp filter for this custom field. + * Supports on, before, after, between, isPresent operations. + * + * @return TimestampFilter for the custom field + */ + public TimestampFilter timestampFilter() { + return new TimestampFilter<>(fieldName, builder, params) + .supportsPresenceOperator(true); + } + + /** + * Create a boolean filter for this custom field. + * Supports is, isPresent operations. + * + * @return BooleanFilter for the custom field + */ + public BooleanFilter booleanFilter() { + return new BooleanFilter<>(fieldName, builder, params); + } +} diff --git a/src/main/java/com/chargebee/v4/models/addon/params/AddonListParams.java b/src/main/java/com/chargebee/v4/models/addon/params/AddonListParams.java index b5d808bf..1121c762 100644 --- a/src/main/java/com/chargebee/v4/models/addon/params/AddonListParams.java +++ b/src/main/java/com/chargebee/v4/models/addon/params/AddonListParams.java @@ -12,6 +12,8 @@ import com.chargebee.v4.filters.NumberFilter; import com.chargebee.v4.filters.TimestampFilter; +import com.chargebee.v4.filters.CustomFieldSelector; + import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -110,6 +112,19 @@ public AddonListBuilder includeDeleted(Boolean value) { return this; } + /** + * Create a filter for a custom field. + * + * @param fieldName the custom field name (must contain "cf_") + * @return CustomFieldSelector for choosing filter type + */ + public CustomFieldSelector customField(String fieldName) { + if (fieldName == null || !fieldName.contains("cf_")) { + throw new IllegalArgumentException("Custom field name must contain 'cf_'"); + } + return new CustomFieldSelector<>(fieldName, this, queryParams); + } + public AddonListParams build() { return new AddonListParams(this); } diff --git a/src/main/java/com/chargebee/v4/models/coupon/params/CouponListParams.java b/src/main/java/com/chargebee/v4/models/coupon/params/CouponListParams.java index 502d4ff9..447d6151 100644 --- a/src/main/java/com/chargebee/v4/models/coupon/params/CouponListParams.java +++ b/src/main/java/com/chargebee/v4/models/coupon/params/CouponListParams.java @@ -11,6 +11,8 @@ import com.chargebee.v4.filters.StringFilter; import com.chargebee.v4.filters.TimestampFilter; +import com.chargebee.v4.filters.CustomFieldSelector; + import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -99,6 +101,19 @@ public ApplicableItemPriceIdsFilter applicableItemPriceIds() { return new ApplicableItemPriceIdsFilter("applicable_item_price_ids", this, queryParams); } + /** + * Create a filter for a custom field. + * + * @param fieldName the custom field name (must contain "cf_") + * @return CustomFieldSelector for choosing filter type + */ + public CustomFieldSelector customField(String fieldName) { + if (fieldName == null || !fieldName.contains("cf_")) { + throw new IllegalArgumentException("Custom field name must contain 'cf_'"); + } + return new CustomFieldSelector<>(fieldName, this, queryParams); + } + public CouponListParams build() { return new CouponListParams(this); } diff --git a/src/main/java/com/chargebee/v4/models/customer/params/CustomerListParams.java b/src/main/java/com/chargebee/v4/models/customer/params/CustomerListParams.java index d9ef947e..a4d75587 100644 --- a/src/main/java/com/chargebee/v4/models/customer/params/CustomerListParams.java +++ b/src/main/java/com/chargebee/v4/models/customer/params/CustomerListParams.java @@ -11,6 +11,8 @@ import com.chargebee.v4.filters.StringFilter; import com.chargebee.v4.filters.TimestampFilter; +import com.chargebee.v4.filters.CustomFieldSelector; + import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -125,6 +127,19 @@ public CustomerListBuilder relationship(RelationshipParams value) { return this; } + /** + * Create a filter for a custom field. + * + * @param fieldName the custom field name (must contain "cf_") + * @return CustomFieldSelector for choosing filter type + */ + public CustomFieldSelector customField(String fieldName) { + if (fieldName == null || !fieldName.contains("cf_")) { + throw new IllegalArgumentException("Custom field name must contain 'cf_'"); + } + return new CustomFieldSelector<>(fieldName, this, queryParams); + } + public CustomerListParams build() { return new CustomerListParams(this); } diff --git a/src/main/java/com/chargebee/v4/models/feature/params/FeatureListParams.java b/src/main/java/com/chargebee/v4/models/feature/params/FeatureListParams.java index d8ae9356..7e6db631 100644 --- a/src/main/java/com/chargebee/v4/models/feature/params/FeatureListParams.java +++ b/src/main/java/com/chargebee/v4/models/feature/params/FeatureListParams.java @@ -10,6 +10,8 @@ import com.chargebee.v4.internal.Recommended; import com.chargebee.v4.filters.StringFilter; +import com.chargebee.v4.filters.CustomFieldSelector; + import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -70,6 +72,19 @@ public TypeFilter type() { return new TypeFilter("type", this, queryParams); } + /** + * Create a filter for a custom field. + * + * @param fieldName the custom field name (must contain "cf_") + * @return CustomFieldSelector for choosing filter type + */ + public CustomFieldSelector customField(String fieldName) { + if (fieldName == null || !fieldName.contains("cf_")) { + throw new IllegalArgumentException("Custom field name must contain 'cf_'"); + } + return new CustomFieldSelector<>(fieldName, this, queryParams); + } + public FeatureListParams build() { return new FeatureListParams(this); } diff --git a/src/main/java/com/chargebee/v4/models/itemFamily/params/ItemFamilyListParams.java b/src/main/java/com/chargebee/v4/models/itemFamily/params/ItemFamilyListParams.java index 780c9c3b..b6bf7124 100644 --- a/src/main/java/com/chargebee/v4/models/itemFamily/params/ItemFamilyListParams.java +++ b/src/main/java/com/chargebee/v4/models/itemFamily/params/ItemFamilyListParams.java @@ -11,6 +11,8 @@ import com.chargebee.v4.filters.StringFilter; import com.chargebee.v4.filters.TimestampFilter; +import com.chargebee.v4.filters.CustomFieldSelector; + import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -75,6 +77,19 @@ public IncludeSiteLevelResourcesFilter includeSiteLevelResources() { return new IncludeSiteLevelResourcesFilter("include_site_level_resources", this, queryParams); } + /** + * Create a filter for a custom field. + * + * @param fieldName the custom field name (must contain "cf_") + * @return CustomFieldSelector for choosing filter type + */ + public CustomFieldSelector customField(String fieldName) { + if (fieldName == null || !fieldName.contains("cf_")) { + throw new IllegalArgumentException("Custom field name must contain 'cf_'"); + } + return new CustomFieldSelector<>(fieldName, this, queryParams); + } + public ItemFamilyListParams build() { return new ItemFamilyListParams(this); } diff --git a/src/main/java/com/chargebee/v4/models/plan/params/PlanListParams.java b/src/main/java/com/chargebee/v4/models/plan/params/PlanListParams.java index 4dfede48..f626fba8 100644 --- a/src/main/java/com/chargebee/v4/models/plan/params/PlanListParams.java +++ b/src/main/java/com/chargebee/v4/models/plan/params/PlanListParams.java @@ -12,6 +12,8 @@ import com.chargebee.v4.filters.NumberFilter; import com.chargebee.v4.filters.TimestampFilter; +import com.chargebee.v4.filters.CustomFieldSelector; + import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -122,6 +124,19 @@ public PlanListBuilder includeDeleted(Boolean value) { return this; } + /** + * Create a filter for a custom field. + * + * @param fieldName the custom field name (must contain "cf_") + * @return CustomFieldSelector for choosing filter type + */ + public CustomFieldSelector customField(String fieldName) { + if (fieldName == null || !fieldName.contains("cf_")) { + throw new IllegalArgumentException("Custom field name must contain 'cf_'"); + } + return new CustomFieldSelector<>(fieldName, this, queryParams); + } + public PlanListParams build() { return new PlanListParams(this); } diff --git a/src/main/java/com/chargebee/v4/models/quote/params/QuoteListParams.java b/src/main/java/com/chargebee/v4/models/quote/params/QuoteListParams.java index a1205cad..7b1de744 100644 --- a/src/main/java/com/chargebee/v4/models/quote/params/QuoteListParams.java +++ b/src/main/java/com/chargebee/v4/models/quote/params/QuoteListParams.java @@ -11,6 +11,8 @@ import com.chargebee.v4.filters.StringFilter; import com.chargebee.v4.filters.TimestampFilter; +import com.chargebee.v4.filters.CustomFieldSelector; + import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -88,6 +90,19 @@ public SortBySortBuilder sortBy() { return new SortBySortBuilder("sort_by", this); } + /** + * Create a filter for a custom field. + * + * @param fieldName the custom field name (must contain "cf_") + * @return CustomFieldSelector for choosing filter type + */ + public CustomFieldSelector customField(String fieldName) { + if (fieldName == null || !fieldName.contains("cf_")) { + throw new IllegalArgumentException("Custom field name must contain 'cf_'"); + } + return new CustomFieldSelector<>(fieldName, this, queryParams); + } + public QuoteListParams build() { return new QuoteListParams(this); } diff --git a/src/main/java/com/chargebee/v4/models/subscription/params/SubscriptionListParams.java b/src/main/java/com/chargebee/v4/models/subscription/params/SubscriptionListParams.java index 0edf5437..06511e02 100644 --- a/src/main/java/com/chargebee/v4/models/subscription/params/SubscriptionListParams.java +++ b/src/main/java/com/chargebee/v4/models/subscription/params/SubscriptionListParams.java @@ -12,6 +12,8 @@ import com.chargebee.v4.filters.NumberFilter; import com.chargebee.v4.filters.TimestampFilter; +import com.chargebee.v4.filters.CustomFieldSelector; + import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -145,6 +147,19 @@ public PlanIdFilter planId() { return new PlanIdFilter("plan_id", this, queryParams); } + /** + * Create a filter for a custom field. + * + * @param fieldName the custom field name (must contain "cf_") + * @return CustomFieldSelector for choosing filter type + */ + public CustomFieldSelector customField(String fieldName) { + if (fieldName == null || !fieldName.contains("cf_")) { + throw new IllegalArgumentException("Custom field name must contain 'cf_'"); + } + return new CustomFieldSelector<>(fieldName, this, queryParams); + } + public SubscriptionListParams build() { return new SubscriptionListParams(this); }