diff --git a/.codegraph/.gitignore b/.codegraph/.gitignore
index 9de0f16..d20c0fe 100644
--- a/.codegraph/.gitignore
+++ b/.codegraph/.gitignore
@@ -1,16 +1,5 @@
-# CodeGraph data files
-# These are local to each machine and should not be committed
-
-# Database
-*.db
-*.db-wal
-*.db-shm
-
-# Cache
-cache/
-
-# Logs
-*.log
-
-# Hook markers
-.dirty
+# CodeGraph data files — local to each machine, not for committing.
+# Ignore everything in .codegraph/ except this file itself, so transient
+# files (the database, daemon.pid, sockets, logs) never show up in git.
+*
+!.gitignore
diff --git a/loyalty-mcp-server/pom.xml b/loyalty-mcp-server/pom.xml
index f218feb..ed8df38 100644
--- a/loyalty-mcp-server/pom.xml
+++ b/loyalty-mcp-server/pom.xml
@@ -21,6 +21,11 @@
spring-boot-starter-web
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
org.springframework.ai
spring-ai-starter-mcp-server-webmvc
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/McpServerApplication.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/McpServerApplication.java
index e4f2701..1c1900c 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/McpServerApplication.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/McpServerApplication.java
@@ -3,7 +3,11 @@ package dev.sonpx.loyalty.mcp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-@SpringBootApplication
+@SpringBootApplication(excludeName = {
+ "org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration",
+ "org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration",
+ "org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration"
+})
public class McpServerApplication {
public static void main(String[] args) {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/api/MemberTierApiClient.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/api/MemberTierApiClient.java
index 1292d79..6375b6d 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/api/MemberTierApiClient.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/api/MemberTierApiClient.java
@@ -1,9 +1,8 @@
package dev.sonpx.loyalty.mcp.client.api;
import dev.sonpx.loyalty.mcp.client.model.MemberTier;
-import org.springframework.web.service.annotation.GetExchange;
-
import java.util.List;
+import org.springframework.web.service.annotation.GetExchange;
public interface MemberTierApiClient {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/api/PointPoolApiClient.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/api/PointPoolApiClient.java
index ee8f0bb..6a0c41c 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/api/PointPoolApiClient.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/api/PointPoolApiClient.java
@@ -1,9 +1,8 @@
package dev.sonpx.loyalty.mcp.client.api;
import dev.sonpx.loyalty.mcp.client.model.PointPool;
-import org.springframework.web.service.annotation.GetExchange;
-
import java.util.List;
+import org.springframework.web.service.annotation.GetExchange;
public interface PointPoolApiClient {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/PointPool.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/PointPool.java
index a780d4a..9a13883 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/PointPool.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/PointPool.java
@@ -1,7 +1,6 @@
package dev.sonpx.loyalty.mcp.client.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-
import java.math.BigDecimal;
@JsonIgnoreProperties(ignoreUnknown = true)
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/reward/CampaignDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/reward/CampaignDto.java
index b93fe64..684275d 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/reward/CampaignDto.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/reward/CampaignDto.java
@@ -2,10 +2,9 @@ package dev.sonpx.loyalty.mcp.client.model.reward;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.Data;
-
import java.util.LinkedHashMap;
import java.util.Map;
+import lombok.Data;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/reward/CampaignRuleDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/reward/CampaignRuleDto.java
index 5e64954..cf20ce9 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/reward/CampaignRuleDto.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/client/model/reward/CampaignRuleDto.java
@@ -2,10 +2,9 @@ package dev.sonpx.loyalty.mcp.client.model.reward;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonValue;
-import lombok.Data;
-
import java.time.OffsetDateTime;
import java.util.List;
+import lombok.Data;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/ApiClientConfig.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/ApiClientConfig.java
index 40b11f7..4cc4ade 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/ApiClientConfig.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/ApiClientConfig.java
@@ -3,7 +3,6 @@ package dev.sonpx.loyalty.mcp.config;
import dev.sonpx.loyalty.mcp.client.api.CampaignApiClient;
import dev.sonpx.loyalty.mcp.client.api.MemberTierApiClient;
import dev.sonpx.loyalty.mcp.client.api.PointPoolApiClient;
-
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
@@ -28,7 +27,6 @@ public class ApiClientConfig {
private String coreBaseUrl;
-
@Bean
public RestClient loyaltyRestClient(OAuth2AuthorizedClientManager authorizedClientManager) {
return RestClient.builder()
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/AppConfig.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/AppConfig.java
new file mode 100644
index 0000000..b2a0bee
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/AppConfig.java
@@ -0,0 +1,17 @@
+package dev.sonpx.loyalty.mcp.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Created by SonPhung on Sunday, 19-Jul-2026
+ **/
+@Configuration
+public class AppConfig {
+
+ @Bean
+ public ObjectMapper objectMapper() {
+ return new ObjectMapper();
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/AsyncTimeoutFilter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/AsyncTimeoutFilter.java
index 18c6e74..9fd61f2 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/AsyncTimeoutFilter.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/AsyncTimeoutFilter.java
@@ -4,11 +4,10 @@ import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
-import java.io.IOException;
-
@Component
public class AsyncTimeoutFilter extends OncePerRequestFilter {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/ClientConfig.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/ClientConfig.java
new file mode 100644
index 0000000..a9d8743
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/ClientConfig.java
@@ -0,0 +1,57 @@
+package dev.sonpx.loyalty.mcp.config;
+
+import static org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId;
+import static org.springframework.security.oauth2.client.web.client.RequestAttributePrincipalResolver.principal;
+
+import dev.sonpx.loyalty.mcp.reward.client.RewardClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
+import org.springframework.security.oauth2.client.web.client.OAuth2ClientHttpRequestInterceptor;
+import org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver;
+import org.springframework.security.oauth2.client.web.client.RequestAttributePrincipalResolver;
+import org.springframework.web.client.RestClient;
+import org.springframework.web.client.support.RestClientAdapter;
+import org.springframework.web.service.invoker.HttpServiceProxyFactory;
+
+/**
+ * Created by SonPhung on Sunday, 19-Jul-2026
+ **/
+@Configuration
+public class ClientConfig {
+
+ @Value("${loyalty.core.base-url}")
+ private String coreBaseUrl;
+
+ @Bean
+ public RestClient rewardReClient(OAuth2AuthorizedClientManager authorizedClientManager) {
+ OAuth2ClientHttpRequestInterceptor oauth2Interceptor =
+ new OAuth2ClientHttpRequestInterceptor(authorizedClientManager);
+ oauth2Interceptor.setClientRegistrationIdResolver(new RequestAttributeClientRegistrationIdResolver());
+ oauth2Interceptor.setPrincipalResolver(new RequestAttributePrincipalResolver());
+
+ return RestClient.builder()
+ .baseUrl(coreBaseUrl + "/svc/reward")
+ .requestInterceptor((request, body, execution) -> {
+ clientRegistrationId("keycloak").accept(request.getAttributes());
+ principal("loyalty-service").accept(request.getAttributes());
+ return oauth2Interceptor.intercept(request, body, execution);
+ })
+ .build();
+ }
+
+
+ @Bean
+ public HttpServiceProxyFactory httpServiceProxyFactory(RestClient rewardReClient) {
+ return HttpServiceProxyFactory.builderFor(RestClientAdapter.create(rewardReClient))
+ .customArgumentResolver(new PageableArgumentResolver())
+ .customArgumentResolver(new PojoArgumentResolver())
+ .build();
+ }
+
+ @Bean
+ public RewardClient rewardClient(HttpServiceProxyFactory httpServiceProxyFactory) {
+ return httpServiceProxyFactory.createClient(RewardClient.class);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/McpServerConfig.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/McpServerConfig.java
index b2032ef..debee66 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/McpServerConfig.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/McpServerConfig.java
@@ -3,7 +3,6 @@ package dev.sonpx.loyalty.mcp.config;
import dev.sonpx.loyalty.mcp.client.api.CampaignApiClient;
import dev.sonpx.loyalty.mcp.client.api.MemberTierApiClient;
import dev.sonpx.loyalty.mcp.client.api.PointPoolApiClient;
-
import dev.sonpx.loyalty.mcp.tool.LoyaltyAgentTools;
import dev.sonpx.loyalty.mcp.tool.reward.CampaignRuleTools;
import org.springframework.context.annotation.Bean;
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/PageableArgumentResolver.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/PageableArgumentResolver.java
new file mode 100644
index 0000000..bf591b7
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/PageableArgumentResolver.java
@@ -0,0 +1,31 @@
+package dev.sonpx.loyalty.mcp.config;
+
+import org.springframework.core.MethodParameter;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.web.service.invoker.HttpRequestValues;
+import org.springframework.web.service.invoker.HttpServiceArgumentResolver;
+
+public class PageableArgumentResolver implements HttpServiceArgumentResolver {
+ @Override
+ public boolean resolve(Object argument, MethodParameter parameter, HttpRequestValues.Builder requestValues) {
+ if (!Pageable.class.isAssignableFrom(parameter.getParameterType())) {
+ return false;
+ }
+
+ if (argument instanceof Pageable pageable) {
+ if (pageable.isPaged()) {
+ requestValues.addRequestParameter("page", String.valueOf(pageable.getPageNumber()));
+ requestValues.addRequestParameter("size", String.valueOf(pageable.getPageSize()));
+ }
+
+ Sort sort = pageable.getSort();
+ if (sort.isSorted()) {
+ for (Sort.Order order : sort) {
+ requestValues.addRequestParameter("sort", order.getProperty() + "," + order.getDirection().name());
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/PojoArgumentResolver.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/PojoArgumentResolver.java
new file mode 100644
index 0000000..6310bbe
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/PojoArgumentResolver.java
@@ -0,0 +1,66 @@
+package dev.sonpx.loyalty.mcp.config;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.core.MethodParameter;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.service.invoker.HttpRequestValues;
+import org.springframework.web.service.invoker.HttpServiceArgumentResolver;
+import org.springframework.data.domain.Pageable;
+
+import java.util.Map;
+
+public class PojoArgumentResolver implements HttpServiceArgumentResolver {
+ private final ObjectMapper objectMapper;
+
+ public PojoArgumentResolver() {
+ this.objectMapper = new ObjectMapper();
+ }
+
+ @Override
+ public boolean resolve(Object argument, MethodParameter parameter, HttpRequestValues.Builder requestValues) {
+ // Skip if parameter is annotated with typical HTTP interface annotations
+ if (parameter.hasParameterAnnotation(RequestParam.class) ||
+ parameter.hasParameterAnnotation(RequestBody.class) ||
+ parameter.hasParameterAnnotation(PathVariable.class)) {
+ return false;
+ }
+
+ // Skip basic types and Pageable
+ if (parameter.getParameterType().isPrimitive() ||
+ parameter.getParameterType().getName().startsWith("java.lang") ||
+ Pageable.class.isAssignableFrom(parameter.getParameterType())) {
+ return false;
+ }
+
+ if (argument == null) {
+ return true;
+ }
+
+ Map map = objectMapper.convertValue(argument, new TypeReference<>() {});
+ flattenMap("", map, requestValues);
+ return true;
+ }
+
+ private void flattenMap(String prefix, Map map, HttpRequestValues.Builder requestValues) {
+ for (Map.Entry entry : map.entrySet()) {
+ String key = prefix.isEmpty() ? entry.getKey() : prefix + "." + entry.getKey();
+ Object value = entry.getValue();
+ if (value instanceof Map) {
+ @SuppressWarnings("unchecked")
+ Map nestedMap = (Map) value;
+ flattenMap(key, nestedMap, requestValues);
+ } else if (value instanceof Iterable> iterable) {
+ for (Object item : iterable) {
+ if (item != null) {
+ requestValues.addRequestParameter(key, String.valueOf(item));
+ }
+ }
+ } else if (value != null) {
+ requestValues.addRequestParameter(key, String.valueOf(value));
+ }
+ }
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/SecurityConfig.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/SecurityConfig.java
index 63cbd7e..beb2a17 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/SecurityConfig.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/config/SecurityConfig.java
@@ -4,11 +4,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
+import org.springframework.security.oauth2.client.*;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.web.SecurityFilterChain;
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/criteria/AbstractFwCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/criteria/AbstractFwCriteria.java
new file mode 100644
index 0000000..26bdb66
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/criteria/AbstractFwCriteria.java
@@ -0,0 +1,38 @@
+
+package dev.sonpx.loyalty.mcp.criteria;
+
+
+import dev.sonpx.loyalty.mcp.filter.RangeFilter;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import lombok.Data;
+
+/**
+ * @author AnhDT Created on 2025/05/23
+ */
+@Data
+public abstract class AbstractFwCriteria implements FwCriteria {
+
+ protected StringFilter status;
+ protected RangeFilter lastUpdateDate;
+
+ // for search text
+ protected String search;
+ protected String searchComponent;
+
+ //Handle URL-encoded search text (e.g. "%20", "%23") received from UI
+ //e.g: search=tìm%20kiếm -> tìm kiếm
+ public void setSearch(String search) {
+ try {
+ this.search = search == null ? null : URLDecoder.decode(search, StandardCharsets.UTF_8);
+ } catch (IllegalArgumentException e) {
+ this.search = search;
+ }
+ }
+
+ protected abstract String[] getColumns();
+
+ protected abstract String[] getComponentColumns();
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/criteria/FwCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/criteria/FwCriteria.java
new file mode 100644
index 0000000..3f5f93c
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/criteria/FwCriteria.java
@@ -0,0 +1,13 @@
+
+package dev.sonpx.loyalty.mcp.criteria;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+
+/**
+ * Created by SonPhung on Tuesday, 10-Oct-2023
+ */
+@JsonIgnoreProperties(value = {"columns", "columnsComponent"})
+public interface FwCriteria {
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/DraftSessionManager.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/DraftSessionManager.java
index 311e31c..bc401e4 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/DraftSessionManager.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/DraftSessionManager.java
@@ -1,13 +1,12 @@
package dev.sonpx.loyalty.mcp.draft;
import dev.sonpx.loyalty.mcp.draft.model.DraftSession;
-import org.springframework.stereotype.Component;
-
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
+import org.springframework.stereotype.Component;
@Component
public class DraftSessionManager {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/CampaignDraft.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/CampaignDraft.java
index 574ccc5..dc8bd95 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/CampaignDraft.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/CampaignDraft.java
@@ -2,10 +2,9 @@ package dev.sonpx.loyalty.mcp.draft.model;
import dev.sonpx.loyalty.mcp.client.model.reward.CampaignDto;
import dev.sonpx.loyalty.mcp.client.model.reward.CampaignRuleDto;
-import lombok.Data;
-
import java.util.ArrayList;
import java.util.List;
+import lombok.Data;
@Data
public class CampaignDraft {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/DraftSession.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/DraftSession.java
index b89d45d..1802c18 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/DraftSession.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/DraftSession.java
@@ -1,8 +1,7 @@
package dev.sonpx.loyalty.mcp.draft.model;
-import lombok.Data;
-
import java.time.Instant;
+import lombok.Data;
@Data
public class DraftSession {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/PoolDraft.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/PoolDraft.java
index 866fe41..1082b3f 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/PoolDraft.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/draft/model/PoolDraft.java
@@ -1,8 +1,8 @@
package dev.sonpx.loyalty.mcp.draft.model;
-import lombok.Data;
import java.util.HashMap;
import java.util.Map;
+import lombok.Data;
@Data
public class PoolDraft {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/AttributeDataType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/AttributeDataType.java
new file mode 100644
index 0000000..0a49879
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/AttributeDataType.java
@@ -0,0 +1,25 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum AttributeDataType {
+ STRING("STRING"),
+ NUMBER("NUMBER"),
+ DATE("DATE"),
+ BOOLEAN("BOOLEAN"),
+ TIME("TIME");
+
+ private final String code;
+
+ public static AttributeDataType fromCode(String code) {
+ return Arrays.stream(AttributeDataType.values())
+ .filter(o -> code.equals(o.getCode()))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/AttributeEntityType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/AttributeEntityType.java
new file mode 100644
index 0000000..0073626
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/AttributeEntityType.java
@@ -0,0 +1,37 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author Phudao
+ * Created on 2024/01/12
+ */
+@Getter
+@RequiredArgsConstructor
+public enum AttributeEntityType {
+ CLIENT("CLIENT"),
+ PRODUCT_ACCOUNT("PRODUCT_ACCOUNT"),
+ CARD("CARD"),
+ CORPORATION("CORPORATION"),
+ CHAIN("CHAIN"),
+ STORE("STORE"),
+ // TRANSACTIONS("TRANSACTIONS"),
+ CAMPAIGN("CAMPAIGN"),
+ ITEM("ITEM");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static AttributeEntityType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/AttributeType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/AttributeType.java
new file mode 100644
index 0000000..1997b0c
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/AttributeType.java
@@ -0,0 +1,27 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum AttributeType {
+ CUSTOM("CUSTOM"),
+ DYNAMIC("DYNAMIC"),
+ STATIC("STATIC");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static AttributeType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CodeEnumLookup.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CodeEnumLookup.java
new file mode 100644
index 0000000..bc10526
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CodeEnumLookup.java
@@ -0,0 +1,43 @@
+package dev.sonpx.loyalty.mcp.enums;
+
+import java.lang.reflect.Method;
+import java.util.Optional;
+
+public final class CodeEnumLookup {
+
+ private CodeEnumLookup() {}
+
+ public static T resolve(String source, Class targetType) {
+ if (source == null || source.isBlank()) {
+ return null;
+ }
+
+ String normalized = source.trim();
+ for (T constant : targetType.getEnumConstants()) {
+ if (constant.name().equalsIgnoreCase(normalized)
+ || codeOf(constant).map(code -> code.equalsIgnoreCase(normalized)).orElse(false)) {
+ return constant;
+ }
+ }
+
+ throw new IllegalArgumentException("Unsupported " + targetType.getSimpleName() + " value: " + source);
+ }
+
+ public static String codeOfEnum(Enum> constant) {
+ return codeOf(constant).orElseGet(constant::name);
+ }
+
+ private static Optional codeOf(Object constant) {
+ if (constant instanceof EnumBase enumBase) {
+ return Optional.ofNullable(enumBase.getCode());
+ }
+
+ try {
+ Method getCode = constant.getClass().getMethod("getCode");
+ Object code = getCode.invoke(constant);
+ return code instanceof String value ? Optional.of(value) : Optional.empty();
+ } catch (ReflectiveOperationException ex) {
+ return Optional.empty();
+ }
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CounterBucket.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CounterBucket.java
new file mode 100644
index 0000000..a936950
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CounterBucket.java
@@ -0,0 +1,27 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum CounterBucket {
+ CURRENT_BUCKET("CB"),
+ PREVIOUS_BUCKET("PB"),
+ PERIOD_BEFORE_LAST("PBL");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static CounterBucket fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CounterEntity.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CounterEntity.java
new file mode 100644
index 0000000..bcb329e
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CounterEntity.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum CounterEntity {
+ CUSTOMER("CU"),
+ ACCOUNT("AC"),
+ CARD("CA"),
+ MERCHANT("ME"),
+ SYSTEM("SY");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static CounterEntity fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CounterPeriod.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CounterPeriod.java
new file mode 100644
index 0000000..af7bd03
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/CounterPeriod.java
@@ -0,0 +1,42 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Wednesday, 20-Dec-2023
+ */
+@Getter
+@RequiredArgsConstructor
+public enum CounterPeriod {
+ AOD_ANNIVERSARY("AA"),
+ DAY_COUNTER("DC"),
+ DAYS_FROM_AOD("DFA"),
+ DAYS_FROM_COD("DFC"),
+ FIXED_DATE("FD"),
+ HALF_YEAR("HY"),
+ MONTHS_FROM_AOD("MFA"),
+ MONTHS_COUNTER("MC"),
+ NON_EXPIRE("NE"),
+ QUARTER_COUNTER("QC"),
+ QUARTER_FROM_AOD("QFA"),
+ WEEK_COUNTER("WC"),
+ YEAR_COUNTER("YC"),
+ STATEMENT_CYCLE("SC");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static CounterPeriod fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/DerivedType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/DerivedType.java
new file mode 100644
index 0000000..46e2e0e
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/DerivedType.java
@@ -0,0 +1,44 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT Created on 2025/11/17
+ */
+@Getter
+@RequiredArgsConstructor
+public enum DerivedType {
+ STRING("STRING", AttributeDataType.STRING),
+ INT("INT", AttributeDataType.NUMBER),
+ DECIMAL("DECIMAL", AttributeDataType.NUMBER),
+ DATE("DATE", AttributeDataType.DATE),
+ TIME("TIME", AttributeDataType.TIME),
+ BOOLEAN("BOOLEAN", AttributeDataType.BOOLEAN),
+ SEGMENT("SEGMENT", null),
+ AUDIENCE("AUDIENCE", null);
+
+ private final String code;
+
+ private final AttributeDataType baseType;
+
+ public static DerivedType fromCode(String code) {
+ return Arrays.stream(DerivedType.values())
+ .filter(o -> code.equals(o.getCode()))
+ .findFirst()
+ .orElse(null);
+ }
+
+ public static DerivedType fromBaseType(AttributeDataType baseType) {
+ return Arrays.stream(DerivedType.values())
+ .filter(o -> baseType.equals(o.getBaseType()))
+ .findFirst()
+ .orElse(null);
+ }
+
+ public static boolean isAudienceType(String code) {
+ return DerivedType.AUDIENCE.code.equalsIgnoreCase(code) || DerivedType.SEGMENT.code.equalsIgnoreCase(code);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/EntityLevel.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/EntityLevel.java
new file mode 100644
index 0000000..eb44b36
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/EntityLevel.java
@@ -0,0 +1,31 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Wednesday, 20-Dec-2023
+ */
+@Getter
+@RequiredArgsConstructor
+public enum EntityLevel {
+ CUSTOMER("CU"),
+ ACCOUNT("AC"),
+ CARD("CA"),
+ LOYALTY_ACCOUNT("LA");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static EntityLevel fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/EnumBase.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/EnumBase.java
new file mode 100644
index 0000000..db430ef
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/EnumBase.java
@@ -0,0 +1,6 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+public interface EnumBase {
+ String getCode();
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/ExpiryPolicy.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/ExpiryPolicy.java
new file mode 100644
index 0000000..f7384c5
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/ExpiryPolicy.java
@@ -0,0 +1,32 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum ExpiryPolicy {
+ FIXED_DATE("FD"),
+ NO_EXPIRY("NE"),
+ ANNUAL_RECURRING_DATE("ARD"),
+ N_MONTHS_FROM_MONTH_OF_EARNING("MF"),
+ N_QUARTERS_FROM_QUARTER_OF_EARNING("QF"),
+ N_YEARS_FROM_YEAR_OF_EARNING("YF"),
+ SEMI_ANNUAL_OR_MID_AND_END_YEAR("SP"),
+ ANNIVERSARY_OF_MEMBERSHIP("AOM");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static ExpiryPolicy fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/FileStoreType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/FileStoreType.java
new file mode 100644
index 0000000..1ed136f
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/FileStoreType.java
@@ -0,0 +1,26 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum FileStoreType {
+ S3("s3"), // For S3 or S3-compatible storage
+ FILE("file"); // For local file system storage
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static FileStoreType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/IErrorCode.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/IErrorCode.java
new file mode 100644
index 0000000..3fb974e
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/IErrorCode.java
@@ -0,0 +1,11 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+/**
+ * Created by SonPhung on Tuesday, 08-Apr-2025
+ */
+public interface IErrorCode {
+ String getCode();
+
+ String name();
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/IdentifierType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/IdentifierType.java
new file mode 100644
index 0000000..9a6a7ac
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/IdentifierType.java
@@ -0,0 +1,14 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+/**
+ * Created by SonPhung on Monday, 27-Nov-2023
+ */
+public enum IdentifierType {
+ MOBILE,
+ CARD,
+ EMAIL,
+ CIF,
+ PAID,
+ PSN,
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/ImageSourceType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/ImageSourceType.java
new file mode 100644
index 0000000..9a5c562
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/ImageSourceType.java
@@ -0,0 +1,27 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public enum ImageSourceType {
+ UPLOAD("UPLOAD"),
+
+ URL("URL");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static ImageSourceType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/JobParamDataType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/JobParamDataType.java
new file mode 100644
index 0000000..c538a24
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/JobParamDataType.java
@@ -0,0 +1,38 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Optional;
+import lombok.Getter;
+
+@Getter
+public enum JobParamDataType {
+ STRING(String.class),
+ LONG(Long.class),
+ INTEGER(Integer.class),
+ DOUBLE(Double.class),
+ FLOAT(Float.class),
+ DATE(Date.class),
+ LOCAL_DATE(LocalDate.class), // yyyy-MM-dd
+ LOCAL_TIME(LocalTime.class),
+ LOCAL_DATE_TIME(LocalDateTime.class); // yyyy-MM-dd'T'HH:mm:ss
+
+ private final Class> type;
+
+ JobParamDataType(Class> type) {
+ this.type = type;
+ }
+
+ public boolean supports(Object value) {
+ return type.isInstance(value);
+ }
+
+ public static Optional resolveType(Object value) {
+ if (value == null) return Optional.empty();
+ return Arrays.stream(values()).filter(t -> t.supports(value)).findFirst();
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/MetaEntityType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/MetaEntityType.java
new file mode 100644
index 0000000..39b2094
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/MetaEntityType.java
@@ -0,0 +1,8 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+public interface MetaEntityType {
+ String getCode();
+
+ String getServiceId();
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/PeriodAction.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/PeriodAction.java
new file mode 100644
index 0000000..65645bc
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/PeriodAction.java
@@ -0,0 +1,11 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+/**
+ * @author AnhDT
+ * Created on 2024/06/26
+ */
+public enum PeriodAction {
+ CURRENT,
+ LAST,
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/PeriodType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/PeriodType.java
new file mode 100644
index 0000000..ba5208d
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/PeriodType.java
@@ -0,0 +1,14 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+/**
+ * @author AnhDT
+ * Created on 2024/06/26
+ */
+public enum PeriodType {
+ YEAR,
+ QUARTER,
+ MONTH,
+ WEEK,
+ DAY,
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/RecordStatus.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/RecordStatus.java
new file mode 100644
index 0000000..181e812
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/RecordStatus.java
@@ -0,0 +1,33 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum RecordStatus implements EnumBase {
+
+ /** Record is active and eligible for processing. DB code: {@code "A"}. */
+ ACTIVE("A"),
+
+ /** Record is logically inactive but retained. DB code: {@code "I"}. */
+ INACTIVE("I"),
+
+ /** Record is marked for deletion. DB code: {@code "D"}. */
+ DELETE("D");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static RecordStatus fromCode(String code) {
+ if (code == null) return null;
+ for (RecordStatus s : values()) {
+ if (s.code.equalsIgnoreCase(code)) return s;
+ }
+ return null;
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/StatisticPeriod.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/StatisticPeriod.java
new file mode 100644
index 0000000..349819b
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/StatisticPeriod.java
@@ -0,0 +1,42 @@
+
+package dev.sonpx.loyalty.mcp.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import java.util.List;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/06/26
+ * {@link #LAST_7_DAYS},
+ * {@link #LAST_30_DAYS},
+ * {@link #LAST_3_MONTHS},
+ * {@link #LAST_6_MONTHS}
+ */
+@Getter
+@RequiredArgsConstructor
+public enum StatisticPeriod {
+ TODAY("TODAY"),
+ LAST_7_DAYS("L7D"),
+ LAST_30_DAYS("L30D"),
+ LAST_3_MONTHS("L3M"),
+ LAST_6_MONTHS("L6M");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static StatisticPeriod fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+
+ public boolean isAny(StatisticPeriod... periods) {
+ return List.of(periods).contains(this);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/DayOfMonth.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/DayOfMonth.java
new file mode 100644
index 0000000..df73dcf
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/DayOfMonth.java
@@ -0,0 +1,56 @@
+
+package dev.sonpx.loyalty.mcp.enums.schedule;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import dev.sonpx.loyalty.mcp.enums.EnumBase;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum DayOfMonth implements EnumBase {
+ DAY01("1"),
+ DAY02("2"),
+ DAY03("3"),
+ DAY04("4"),
+ DAY05("5"),
+ DAY06("6"),
+ DAY07("7"),
+ DAY08("8"),
+ DAY09("9"),
+ DAY10("10"),
+ DAY11("11"),
+ DAY12("12"),
+ DAY13("13"),
+ DAY14("14"),
+ DAY15("15"),
+ DAY16("16"),
+ DAY17("17"),
+ DAY18("18"),
+ DAY19("19"),
+ DAY20("20"),
+ DAY21("21"),
+ DAY22("22"),
+ DAY23("23"),
+ DAY24("24"),
+ DAY25("25"),
+ DAY26("26"),
+ DAY27("27"),
+ DAY28("28"),
+ DAY29("29"),
+ DAY30("30"),
+ DAY31("31");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static DayOfMonth fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(day -> day.getCode().equals(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/DayOfWeek.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/DayOfWeek.java
new file mode 100644
index 0000000..b932584
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/DayOfWeek.java
@@ -0,0 +1,32 @@
+
+package dev.sonpx.loyalty.mcp.enums.schedule;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import dev.sonpx.loyalty.mcp.enums.EnumBase;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum DayOfWeek implements EnumBase {
+ MONDAY("1"),
+ TUESDAY("2"),
+ WEDNESDAY("3"),
+ THURSDAY("4"),
+ FRIDAY("5"),
+ SATURDAY("6"),
+ SUNDAY("7");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static DayOfWeek fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(day -> day.getCode().equals(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/MonthOfYear.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/MonthOfYear.java
new file mode 100644
index 0000000..7e71300
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/MonthOfYear.java
@@ -0,0 +1,37 @@
+
+package dev.sonpx.loyalty.mcp.enums.schedule;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import dev.sonpx.loyalty.mcp.enums.EnumBase;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum MonthOfYear implements EnumBase {
+ JANUARY("1"),
+ FEBRUARY("2"),
+ MARCH("3"),
+ APRIL("4"),
+ MAY("5"),
+ JUNE("6"),
+ JULY("7"),
+ AUGUST("8"),
+ SEPTEMBER("9"),
+ OCTOBER("10"),
+ NOVEMBER("11"),
+ DECEMBER("12");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static MonthOfYear fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(month -> month.getCode().equals(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/PeriodicType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/PeriodicType.java
new file mode 100644
index 0000000..e51692f
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/PeriodicType.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.enums.schedule;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import dev.sonpx.loyalty.mcp.enums.EnumBase;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum PeriodicType implements EnumBase {
+ DAY("D"),
+ WEEK("W"),
+ MONTH("M"),
+ YEAR("Y");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static PeriodicType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(periodicType -> periodicType.getCode().equals(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/ScheduleMonthType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/ScheduleMonthType.java
new file mode 100644
index 0000000..2e78a15
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/ScheduleMonthType.java
@@ -0,0 +1,27 @@
+
+package dev.sonpx.loyalty.mcp.enums.schedule;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import dev.sonpx.loyalty.mcp.enums.EnumBase;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum ScheduleMonthType implements EnumBase {
+ DAY_OF_MONTH("DOM"),
+ DAY_OF_WEEK("DOW");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static ScheduleMonthType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(monthType -> monthType.getCode().equals(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/ScheduleRecurrenceType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/ScheduleRecurrenceType.java
new file mode 100644
index 0000000..ecc1ad7
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/ScheduleRecurrenceType.java
@@ -0,0 +1,27 @@
+
+package dev.sonpx.loyalty.mcp.enums.schedule;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import dev.sonpx.loyalty.mcp.enums.EnumBase;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum ScheduleRecurrenceType implements EnumBase {
+ ONE_TIME("O"),
+ RECURRING("R");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static ScheduleRecurrenceType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(scheduleType -> scheduleType.getCode().equals(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/TriggerMethod.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/TriggerMethod.java
new file mode 100644
index 0000000..b90cc30
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/TriggerMethod.java
@@ -0,0 +1,27 @@
+
+package dev.sonpx.loyalty.mcp.enums.schedule;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import dev.sonpx.loyalty.mcp.enums.EnumBase;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum TriggerMethod implements EnumBase {
+ SCHEDULE("S"),
+ EVENT("E");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static TriggerMethod fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(triggerMethod -> triggerMethod.getCode().equals(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/WeekOfMonth.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/WeekOfMonth.java
new file mode 100644
index 0000000..0b1a1b5
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/enums/schedule/WeekOfMonth.java
@@ -0,0 +1,31 @@
+
+package dev.sonpx.loyalty.mcp.enums.schedule;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import dev.sonpx.loyalty.mcp.enums.EnumBase;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum WeekOfMonth implements EnumBase {
+ FIRST("1"),
+ SECOND("2"),
+ THIRD("3"),
+ FOURTH("4"),
+ FIFTH("5"),
+ LAST("L");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static WeekOfMonth fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(week -> week.getCode().equals(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/BooleanFilter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/BooleanFilter.java
new file mode 100644
index 0000000..ca77a16
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/BooleanFilter.java
@@ -0,0 +1,4 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+public class BooleanFilter extends Filter {}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/DoubleFilter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/DoubleFilter.java
new file mode 100644
index 0000000..52dd09e
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/DoubleFilter.java
@@ -0,0 +1,7 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+/**
+ * @author AnhDT Created on 2025/12/11
+ */
+public class DoubleFilter extends RangeFilter {}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/Filter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/Filter.java
new file mode 100644
index 0000000..68b6ecb
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/Filter.java
@@ -0,0 +1,57 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+/**
+ * Handle for filtering with basic operators (equals, notEquals, specified, in, notIn)
+ */
+@Getter
+@NoArgsConstructor
+@EqualsAndHashCode
+public class Filter implements Serializable {
+
+ private T equals;
+ private T notEquals;
+ private Boolean specified;
+ private List in;
+ private List notIn;
+
+ public Filter(Filter filter) {
+ this.equals = filter.equals;
+ this.notEquals = filter.notEquals;
+ this.specified = filter.specified;
+ this.in = filter.in == null ? null : new ArrayList<>(filter.in);
+ this.notIn = filter.notIn == null ? null : new ArrayList<>(filter.notIn);
+ }
+
+ public Filter setEquals(T equals) {
+ this.equals = equals;
+ return this;
+ }
+
+ public Filter setNotEquals(T notEquals) {
+ this.notEquals = notEquals;
+ return this;
+ }
+
+ public Filter setSpecified(Boolean specified) {
+ this.specified = specified;
+ return this;
+ }
+
+ public Filter setIn(List in) {
+ this.in = in;
+ return this;
+ }
+
+ public Filter setNotIn(List notIn) {
+ this.notIn = notIn;
+ return this;
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/InstantFilter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/InstantFilter.java
new file mode 100644
index 0000000..3df4fc0
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/InstantFilter.java
@@ -0,0 +1,9 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+import java.time.Instant;
+
+/**
+ * @author AnhDT Created on 2025/12/11
+ */
+public class InstantFilter extends RangeFilter {}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/ListContainsFilter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/ListContainsFilter.java
new file mode 100644
index 0000000..37fc8be
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/ListContainsFilter.java
@@ -0,0 +1,31 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+/**
+ * Handle for filtering String type with contains, doesNotContain
+ */
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ListContainsFilter extends Filter {
+
+ private String containsList;
+
+ private String doesNotContainList;
+
+ public ListContainsFilter setContainsList(String contains) {
+ this.containsList = contains;
+ return this;
+ }
+
+ public ListContainsFilter setDoesNotContainList(String doesNotContain) {
+ this.doesNotContainList = doesNotContain;
+ return this;
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/LocalDateFilter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/LocalDateFilter.java
new file mode 100644
index 0000000..0849eb8
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/LocalDateFilter.java
@@ -0,0 +1,9 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+import java.time.LocalDate;
+
+/**
+ * @author AnhDT Created on 2025/12/11
+ */
+public class LocalDateFilter extends RangeFilter {}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/LocalDateTimeFilter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/LocalDateTimeFilter.java
new file mode 100644
index 0000000..2dea15c
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/LocalDateTimeFilter.java
@@ -0,0 +1,9 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author AnhDT Created on 2025/12/11
+ */
+public class LocalDateTimeFilter extends RangeFilter {}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/LongFilter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/LongFilter.java
new file mode 100644
index 0000000..0d724f0
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/LongFilter.java
@@ -0,0 +1,7 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+/**
+ * @author AnhDT Created on 2025/12/11
+ */
+public class LongFilter extends RangeFilter {}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/OlsFilterSpec.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/OlsFilterSpec.java
new file mode 100644
index 0000000..72984c5
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/OlsFilterSpec.java
@@ -0,0 +1,41 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+import java.util.Arrays;
+import java.util.List;
+import lombok.Builder;
+import lombok.Data;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Created by SonPhung on Monday, 09-Oct-2023
+ */
+@Data
+@Builder
+public class OlsFilterSpec {
+
+ private Filter> filter;
+ private String column;
+ private String param;
+ private List columns;
+
+ public boolean searchFilter() {
+ return !CollectionUtils.isEmpty(columns);
+ }
+
+ public static OlsFilterSpec of(Filter> filter, String column, String param) {
+ return OlsFilterSpec.builder()
+ .filter(filter)
+ .column(column)
+ .param(param)
+ .build();
+ }
+
+ public static OlsFilterSpec of(Filter> filter, String param, String... columns) {
+ return OlsFilterSpec.builder()
+ .filter(filter)
+ .columns(Arrays.stream(columns).toList())
+ .param(param)
+ .build();
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/RangeFilter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/RangeFilter.java
new file mode 100644
index 0000000..104da45
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/RangeFilter.java
@@ -0,0 +1,49 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+/**
+ * Handle for filtering comparable types with range options
+ * Include types: Integer, Long, Float, Double, BigDecimal, Instant, LocalDate
+ */
+@Getter
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class RangeFilter> extends Filter {
+
+ private T greaterThan;
+ private T lessThan;
+ private T greaterThanOrEqual;
+ private T lessThanOrEqual;
+
+ public RangeFilter(RangeFilter filter) {
+ super(filter);
+ this.greaterThan = filter.greaterThan;
+ this.lessThan = filter.lessThan;
+ this.greaterThanOrEqual = filter.greaterThanOrEqual;
+ this.lessThanOrEqual = filter.lessThanOrEqual;
+ }
+
+ public RangeFilter setGreaterThan(T greaterThan) {
+ this.greaterThan = greaterThan;
+ return this;
+ }
+
+ public RangeFilter setLessThan(T lessThan) {
+ this.lessThan = lessThan;
+ return this;
+ }
+
+ public RangeFilter setGreaterThanOrEqual(T greaterThanOrEqual) {
+ this.greaterThanOrEqual = greaterThanOrEqual;
+ return this;
+ }
+
+ public RangeFilter setLessThanOrEqual(T lessThanOrEqual) {
+ this.lessThanOrEqual = lessThanOrEqual;
+ return this;
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/ReferenceDataStringFilter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/ReferenceDataStringFilter.java
new file mode 100644
index 0000000..e5fc6df
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/ReferenceDataStringFilter.java
@@ -0,0 +1,12 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+/**
+ * String filter alias for ReferenceData request params such as field.code.equals.
+ */
+public class ReferenceDataStringFilter extends StringFilter {
+
+ public StringFilter getCode() {
+ return this;
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/StringFilter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/StringFilter.java
new file mode 100644
index 0000000..9db36bc
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/filter/StringFilter.java
@@ -0,0 +1,31 @@
+
+package dev.sonpx.loyalty.mcp.filter;
+
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+/**
+ * Handle for filtering String type with contains, doesNotContain
+ */
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class StringFilter extends Filter {
+
+ private String contains;
+
+ private String doesNotContain;
+
+ public StringFilter setContains(String contains) {
+ this.contains = contains;
+ return this;
+ }
+
+ public StringFilter setDoesNotContain(String doesNotContain) {
+ this.doesNotContain = doesNotContain;
+ return this;
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/AttributeData.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/AttributeData.java
new file mode 100644
index 0000000..a46a6b8
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/AttributeData.java
@@ -0,0 +1,36 @@
+
+package dev.sonpx.loyalty.mcp.model;
+
+import java.io.Serial;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * Created by tuanngo on Wed, 10/01/2024
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class AttributeData extends ReferenceData {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ private String attributeType;
+
+ private String dataType;
+
+ private String semanticType;
+
+ private boolean attributeValuePredefined;
+
+ private boolean notFound;
+
+ public AttributeData(String code) {
+ this.code = code;
+ }
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/ProcessResult.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/ProcessResult.java
new file mode 100644
index 0000000..f989dd2
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/ProcessResult.java
@@ -0,0 +1,15 @@
+
+package dev.sonpx.loyalty.mcp.model;
+
+/**
+ * Created by tuanngo on Wed, 2025-09-10
+ */
+public record ProcessResult(String code, String message, String targetId) {
+ public static ProcessResult of(String code, String message) {
+ return new ProcessResult(code, message, null);
+ }
+
+ public static ProcessResult of(String code, String message, String targetId) {
+ return new ProcessResult(code, message, targetId);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/ReferenceData.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/ReferenceData.java
new file mode 100644
index 0000000..c83113b
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/ReferenceData.java
@@ -0,0 +1,75 @@
+
+package dev.sonpx.loyalty.mcp.model;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * Created by tuanngo on Tue, 2025-04-16
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+public class ReferenceData implements Serializable {
+
+ protected String code;
+ protected String description;
+ protected boolean notFound;
+ protected String recordStatus;
+ protected Map attributes = new HashMap<>();
+
+ public ReferenceData(String code) {
+ this.code = code;
+ }
+
+ public ReferenceData(String code, String description) {
+ this.code = code;
+ this.description = description;
+ this.notFound = false;
+ }
+
+ public ReferenceData(String code, String description, Boolean notFound) {
+ this.code = code;
+ this.description = description;
+ this.notFound = notFound;
+ }
+
+ public ReferenceData(String code, String description, boolean notFound, String recordStatus) {
+ this.code = code;
+ this.description = description;
+ this.notFound = notFound;
+ this.recordStatus = recordStatus;
+ }
+
+ public ReferenceData(String code, String description, Map attributes) {
+ this.code = code;
+ this.description = description;
+ this.attributes = attributes;
+ }
+
+ public void addAttribute(String key, Object value) {
+ this.attributes.put(key, value);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ ReferenceData that = (ReferenceData) o;
+ return Objects.equals(code, that.code) && Objects.equals(description, that.description);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(code, description);
+ }
+
+ @Override
+ public String toString() {
+ return "ReferenceData{" + "code='" + code + '\'' + ", notFound=" + notFound + '}';
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/BaseValue.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/BaseValue.java
new file mode 100644
index 0000000..c51f5c5
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/BaseValue.java
@@ -0,0 +1,51 @@
+
+package dev.sonpx.loyalty.mcp.model.valueobject;
+
+import lombok.Getter;
+import lombok.ToString;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+/**
+ * Abstract generic class for value objects.
+ * Provides automatic generation of getter, equals, hashCode, and toString methods
+ * for the 'value' field using Lombok annotations.
+ *
+ * @param the type of the value this class holds
+ */
+@Getter
+@ToString
+public abstract class BaseValue {
+
+ protected T value;
+
+ /**
+ * Constructs a new BaseValue object with the specified value.
+ * @param value the value to set
+ */
+ public BaseValue(T value) {
+ this.value = value;
+ }
+
+ public boolean isNull() {
+ return value == null;
+ }
+
+ public boolean isNotNull() {
+ return value != null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+
+ if (!(o instanceof BaseValue> baseValue)) return false;
+
+ return new EqualsBuilder().append(getValue(), baseValue.getValue()).isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(17, 37).append(getValue()).toHashCode();
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/BooleanValue.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/BooleanValue.java
new file mode 100644
index 0000000..6b0550c
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/BooleanValue.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.model.valueobject;
+
+public class BooleanValue extends BaseValue {
+
+ public static final BooleanValue FALSE = new BooleanValue(false);
+
+ BooleanValue(Boolean value) {
+ super(value);
+ }
+
+ public boolean isEqualTo(BooleanValue compareValue) {
+ return this.value.equals(compareValue.getValue());
+ }
+
+ public static BooleanValue of(Object value) {
+ BooleanValue falseValue = BooleanValue.FALSE;
+ if (value instanceof Boolean bool) {
+ return new BooleanValue(bool);
+ } else if (value instanceof String string) {
+ try {
+ return BooleanValue.of(Boolean.valueOf(string));
+ } catch (Exception ignored) {
+ //
+ }
+ }
+ return falseValue;
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/DateTimeValue.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/DateTimeValue.java
new file mode 100644
index 0000000..a56e8c4
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/DateTimeValue.java
@@ -0,0 +1,307 @@
+
+package dev.sonpx.loyalty.mcp.model.valueobject;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.Map;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+@Slf4j
+@Getter
+public class DateTimeValue extends BaseValue {
+
+ private int quarter = 0;
+
+ public static final DateTimeValue NULL = new DateTimeValue(null);
+
+ public static final DateTimeValue NOW = new DateTimeValue(LocalDateTime.now());
+
+ /**
+ * Mapping of weekday abbreviations to DayOfWeek enums, used by onWeekdays().
+ * Example: "Mon" -> DayOfWeek.MONDAY
+ */
+ public static final Map DAY_OF_WEEK = Map.ofEntries(
+ Map.entry("Mon", DayOfWeek.MONDAY),
+ Map.entry("Tue", DayOfWeek.TUESDAY),
+ Map.entry("Wed", DayOfWeek.WEDNESDAY),
+ Map.entry("Thu", DayOfWeek.THURSDAY),
+ Map.entry("Fri", DayOfWeek.FRIDAY),
+ Map.entry("Sat", DayOfWeek.SATURDAY),
+ Map.entry("Sun", DayOfWeek.SUNDAY));
+
+ /**
+ * Enum representing units of time for plus() and minus() operations.
+ */
+ public enum TimeUnit {
+ DAY,
+ WEEK,
+ MONTH,
+ QUARTER,
+ YEAR,
+ }
+
+ public enum TimeOffset {
+ AGO,
+ AWAY,
+ }
+
+ /**
+ * Private constructor to enforce use of factory method of().
+ * @param value the LocalDateTime to wrap
+ */
+ private DateTimeValue(LocalDateTime value) {
+ super(value);
+ setQuarter();
+ }
+
+ /**
+ * Creates a DateTimeValue from various input types.
+ * - LocalDateTime: Converts to start of day
+ * - LocalDate: Converts to start of day LocalDateTime
+ * - String: Parses ISO ("yyyy-MM-dd") or "dd/MM/yyyy" formats
+ * - Null or invalid: Returns NULL_VALUE
+ *
+ * @param value the input to convert
+ * @return a new DateTimeValue instance
+ */
+ public static DateTimeValue of(Object value) {
+ return switch (value) {
+ case LocalDateTime dateTime -> toStartOfDay(dateTime);
+ case LocalDate localDate -> new DateTimeValue(localDate.atStartOfDay());
+ case String datetimePattern -> parseString(datetimePattern);
+ case null, default -> NULL;
+ };
+ }
+
+ private static DateTimeValue parseString(String datetimePattern) {
+ if (StringUtils.isBlank(datetimePattern)) {
+ return DateTimeValue.NULL;
+ }
+ LocalDateTime localDateTime = LocalDate.parse(datetimePattern).atStartOfDay();
+ return new DateTimeValue(localDateTime);
+ }
+
+ public static DateTimeValue toStartOfDay(LocalDateTime localDateTime) {
+ return new DateTimeValue(localDateTime.toLocalDate().atStartOfDay());
+ }
+
+ /**
+ * Checks if this date falls on any of the specified weekdays.
+ * Example: onWeekdays("Mon", "Fri") returns true if date is a Monday or Friday.
+ *
+ * @param days weekday abbreviations (e.g., "Mon", "Tue")
+ * @return true if the date matches any specified weekday, false if null or no match
+ */
+ public boolean onWeekdays(String... days) {
+ if (isNull()) {
+ return false;
+ }
+ return Arrays.stream(days)
+ .map(DAY_OF_WEEK::get)
+ .anyMatch(dayOfWeek -> dayOfWeek != null && dayOfWeek.equals(value.getDayOfWeek()));
+ }
+
+ /**
+ * Adds a specified quantity of time to this DateTimeValue.
+ * Example: plus(3, TimeUnit. MONTH) adds 3 months.
+ *
+ * @param quantity the amount to add (positive or negative)
+ * @param unit the time unit to apply
+ * @return a new DateTimeValue with the adjusted time
+ * @throws IllegalStateException if this instance is null
+ */
+ public DateTimeValue plus(long quantity, TimeUnit unit) {
+ if (isNull()) {
+ throw new IllegalStateException("Cannot modify a null DateTimeValue");
+ }
+ if (quantity == 0) {
+ return this; // No change
+ }
+ return switch (unit) {
+ case DAY -> DateTimeValue.of(value.plusDays(quantity));
+ case MONTH -> DateTimeValue.of(value.plusMonths(quantity));
+ case QUARTER -> DateTimeValue.of(value.plusMonths(quantity * 3));
+ case YEAR -> DateTimeValue.of(value.plusYears(quantity));
+ case WEEK -> DateTimeValue.of(value.plusWeeks(quantity));
+ default -> NULL;
+ };
+ }
+
+ /**
+ * Subtracts a specified amount of time from this DateTimeValue.
+ * Example: minus(2, TimeUnit.DAY) subtracts 2 days.
+ *
+ * @param amount the amount to subtract (positive; negative values add time)
+ * @param unit the time unit to apply
+ * @return a new DateTimeValue with the adjusted time
+ * @throws IllegalStateException if this instance is null
+ */
+ public DateTimeValue minus(long amount, TimeUnit unit) {
+ if (isNull()) {
+ throw new IllegalStateException("Cannot modify a null DateTimeValue");
+ }
+ if (amount == 0) {
+ return this; // No change
+ }
+ return switch (unit) {
+ case DAY -> DateTimeValue.of(value.minusDays(amount));
+ case MONTH -> DateTimeValue.of(value.minusMonths(amount));
+ case QUARTER -> DateTimeValue.of(value.minusMonths(amount * 3));
+ case YEAR -> DateTimeValue.of(value.minusYears(amount));
+ case WEEK -> DateTimeValue.of(value.minusWeeks(amount));
+ default -> NULL;
+ };
+ }
+
+ /**
+ * Checks if this DateTimeValue is empty (null).
+ *
+ * @return true if null, false otherwise
+ */
+ public boolean isEmpty() {
+ return isNull();
+ }
+
+ /**
+ * Checks if this DateTimeValue is not empty (not null).
+ *
+ * @return true if not null, false otherwise
+ */
+ public boolean isNotEmpty() {
+ return !isNull();
+ }
+
+ /**
+ * Checks if this DateTimeValue equals another, ignoring time of day.
+ * Example: "2025-03-02" equals "2025-03-02".
+ *
+ * @param compareValue the DateTimeValue to compare with
+ * @return true if equal, false if either is null or not equal
+ */
+ public boolean isEquals(DateTimeValue compareValue) {
+ if (isNull()) {
+ return false;
+ }
+ return this.value.isEqual(compareValue.value);
+ }
+
+ /**
+ * Checks if this DateTimeValue is not equal to another.
+ *
+ * @param compareValue the DateTimeValue to compare with
+ * @return true if not equal, false if either is null or equal
+ */
+ public boolean isNotEquals(DateTimeValue compareValue) {
+ return !isEquals(compareValue);
+ }
+
+ /**
+ * Checks if this DateTimeValue is on or after another.
+ * Example: "2025-03-02" isOnOrAfter "2025-03-01" returns true.
+ *
+ * @param compareValue the DateTimeValue to compare with
+ * @return true if on or after, false if either is null or before
+ */
+ public boolean isOnOrAfter(DateTimeValue compareValue) {
+ return value.isAfter(compareValue.value) || value.isEqual(compareValue.value);
+ }
+
+ /**
+ * Checks if this DateTimeValue is on or before another.
+ * Example: "2025-03-02" isOnOrBefore "2025-03-03" returns true.
+ *
+ * @param compareValue the DateTimeValue to compare with
+ * @return true if on or before, false if either is null or after
+ */
+ public boolean isOnOrBefore(DateTimeValue compareValue) {
+ return value.isBefore(compareValue.value) || value.isEqual(compareValue.value);
+ }
+
+ /**
+ * Checks if this DateTimeValue falls between two others (inclusive).
+ * @param from the start of the range
+ * @param to the end of the range
+ * @return true if within range, false if null or outside range
+ */
+ public boolean isBetween(DateTimeValue from, DateTimeValue to) {
+ return isOnOrAfter(from) && isOnOrBefore(to);
+ }
+
+ public boolean quarterAndYearEquals(DateTimeValue compareValue) {
+ if (isNull()) {
+ return false;
+ }
+ return this.quarter == compareValue.quarter && this.value.getYear() == compareValue.value.getYear();
+ }
+
+ public boolean quarterAndYearNotEquals(DateTimeValue compareValue) {
+ return !quarterAndYearEquals(compareValue);
+ }
+
+ private void setQuarter() {
+ if (!isNull()) {
+ this.quarter = (this.value.getMonthValue() - 1) / 3 + 1;
+ }
+ }
+
+ /**
+ * Checks if a date component falls within a specified range.
+ * Example: isInRangeWith(1, 31, TimeUnit.DAY) checks if day is between 1 and 31.
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ * @param timeUnit the unit to check (DAY, MONTH, YEAR)
+ * @return true if within range, false if null or outside range
+ */
+ public boolean isInRangeWith(Integer start, Integer end, TimeUnit timeUnit) {
+ return switch (timeUnit) {
+ case DAY -> value.getDayOfMonth() >= start && value.getDayOfMonth() <= end;
+ case MONTH -> value.getMonthValue() >= start && value.getMonthValue() <= end;
+ case YEAR -> value.getYear() >= start && value.getYear() <= end;
+ case QUARTER -> quarter >= start && quarter <= end;
+ default -> false;
+ };
+ }
+
+ /**
+ * Calculates the difference between this DateTimeValue and another in the specified time unit.
+ * Returns the number of days, months, or years between the two dates, with positive values indicating
+ * this date is after the compared date, and negative values indicating it is before. Only DAY, MONTH,
+ * and YEAR units are supported; other units throw an exception.
+ *
+ * Usage:
+ * DateTimeValue start = DateTimeValue.of("2025-01-01");
+ * DateTimeValue end = DateTimeValue.of("2025-03-02");
+ * Long days = start.differenceInUnits(end, TimeUnit.DAY); // Returns 60 (Jan 1 to Mar 2)
+ * Long months = start.differenceInUnits(end, TimeUnit.MONTH); // Returns 2 (Jan to Mar)
+ * Long years = end.differenceInUnits(start, TimeUnit.YEAR); // Returns 0 (same year)
+ *
+ * Notes:
+ * - Time components are ignored since DateTimeValue normalizes to start of day.
+ * - Returns null if this instance is null; assumes compareValue is non-null (may throw NPE if not).
+ * - Throws UnsupportedOperationException for WEEK or QUARTER units, as they are not implemented.
+ * - The result is signed: positive if this date is after compareValue, negative if before.
+ *
+ * @param compareValue the DateTimeValue to compare against (non-null expected)
+ * @param unit the time unit to measure the difference in (DAY, MONTH, or YEAR)
+ * @return the difference as a Long (positive or negative), or null if this instance is null
+ * @throws UnsupportedOperationException if unit is not DAY, MONTH, or YEAR
+ * @throws NullPointerException if compareValue or its value is null
+ */
+ public Long differenceInUnits(DateTimeValue compareValue, TimeUnit unit) {
+ if (isNull()) {
+ return null;
+ }
+ return switch (unit) {
+ case DAY -> ChronoUnit.DAYS.between(value, compareValue.value);
+ case MONTH -> ChronoUnit.MONTHS.between(value, compareValue.value);
+ case YEAR -> ChronoUnit.YEARS.between(value, compareValue.value);
+ case null, default -> throw new UnsupportedOperationException("Not supported");
+ };
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/NumberValue.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/NumberValue.java
new file mode 100644
index 0000000..cc52882
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/NumberValue.java
@@ -0,0 +1,163 @@
+
+package dev.sonpx.loyalty.mcp.model.valueobject;
+
+public class NumberValue extends BaseValue {
+
+ private static final double EPSILON = 1e-9;
+ public static NumberValue ZERO = new NumberValue(0.0);
+
+ /**
+ * Constructs a new NumberValue object with the specified value.
+ *
+ * @param value the value to set
+ */
+ NumberValue(Double value) {
+ super(value);
+ }
+
+ /**
+ * Create a NumberValue instance from an object.
+ *
+ * @param value an object that could be a Number or String.
+ * @return a NumberValue instance representing the specified value.
+ */
+ public static NumberValue of(Object value) {
+ if (value instanceof Number number) {
+ return new NumberValue(number.doubleValue());
+ } else if (value instanceof String string) {
+ return new NumberValue(Double.parseDouble(string));
+ }
+ return new NumberValue(null);
+ }
+
+ /**
+ * Check if the current NumberValue equals another NumberValue.
+ *
+ * @param compareValue the NumberValue to compare with.
+ * @return true if the current NumberValue is equal to compareValue, otherwise false.
+ */
+ public boolean equals(NumberValue compareValue) {
+ if (this.isNull()) {
+ return false;
+ }
+ return Math.abs(this.value - compareValue.value) < EPSILON;
+ }
+
+ /**
+ * Check if the current NumberValue is not equal to another NumberValue.
+ *
+ * @param compareValue the NumberValue to compare with.
+ * @return true if the current NumberValue is not equal to compareValue, otherwise false.
+ */
+ public boolean notEquals(NumberValue compareValue) {
+ if (this.isNull()) {
+ return false;
+ }
+ return !equals(compareValue);
+ }
+
+ /**
+ * Check if the current NumberValue is less than another NumberValue.
+ *
+ * @param compareValue the NumberValue to compare with.
+ * @return true if the current NumberValue is less than compareValue, otherwise false.
+ */
+ public boolean lessThan(NumberValue compareValue) {
+ if (this.isNull()) {
+ return false;
+ }
+ return this.value < compareValue.value;
+ }
+
+ /**
+ * Check if the current NumberValue is less than or equal to another NumberValue.
+ *
+ * @param compareValue the NumberValue to compare with.
+ * @return true if the current NumberValue is less than or equal to compareValue, otherwise false.
+ */
+ public boolean lessThanOrEqual(NumberValue compareValue) {
+ if (this.isNull()) {
+ return false;
+ }
+ return this.value < compareValue.value || equals(compareValue);
+ }
+
+ /**
+ * Check if the current NumberValue is greater than another NumberValue.
+ *
+ * @param compareValue the NumberValue to compare with.
+ * @return true if the current NumberValue is greater than compareValue, otherwise false.
+ */
+ public boolean greaterThan(NumberValue compareValue) {
+ if (this.isNull()) {
+ return false;
+ }
+ return this.value > compareValue.value;
+ }
+
+ /**
+ * Check if the current NumberValue is greater than or equal to another NumberValue.
+ *
+ * @param compareValue the NumberValue to compare with.
+ * @return true if the current NumberValue is greater than or equal to compareValue, otherwise false.
+ */
+ public boolean greaterThanOrEqual(NumberValue compareValue) {
+ if (this.isNull()) {
+ return false;
+ }
+ return this.value > compareValue.value || equals(compareValue);
+ }
+
+ /**
+ * Check if the current NumberValue is between two other NumberValues.
+ *
+ * @param start the starting NumberValue (inclusive).
+ * @param end the ending NumberValue (inclusive).
+ * @return true if the current NumberValue is between start and end, otherwise false.
+ */
+ public boolean between(NumberValue start, NumberValue end) {
+ if (this.isNull()) {
+ return false;
+ } else if (start.isNull()) {
+ return lessThanOrEqual(end);
+ } else if (end.isNull()) {
+ return greaterThanOrEqual(start);
+ }
+ return this.greaterThanOrEqual(start) && this.lessThanOrEqual(end);
+ }
+
+ public Long toLong() {
+ if (this.isNull()) {
+ return null;
+ }
+ return this.value.longValue();
+ }
+
+ public NumberValue min(NumberValue with) {
+ return new NumberValue(Math.min(this.value, with.value));
+ }
+
+ public NumberValue max(NumberValue with) {
+ return new NumberValue(Math.max(this.value, with.value));
+ }
+
+ public NumberValue add(NumberValue with) {
+ return new NumberValue(this.value + with.value);
+ }
+
+ public NumberValue subtract(NumberValue with) {
+ return new NumberValue(this.value - with.value);
+ }
+
+ public NumberValue multiply(NumberValue with) {
+ return new NumberValue(this.value * with.value);
+ }
+
+ public NumberValue divide(NumberValue with) {
+ return new NumberValue(this.value / with.value);
+ }
+
+ public NumberValue percent(Integer value) {
+ return new NumberValue((this.value * value) / 100);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/StringValue.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/StringValue.java
new file mode 100644
index 0000000..732a2de
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/StringValue.java
@@ -0,0 +1,250 @@
+
+package dev.sonpx.loyalty.mcp.model.valueobject;
+
+import java.util.Arrays;
+import java.util.regex.PatternSyntaxException;
+import lombok.ToString;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Strings;
+
+@Slf4j
+@ToString
+public class StringValue extends BaseValue {
+
+ public static final StringValue EMPTY = new StringValue("");
+ public static final String PIPE_DELIMITED = "|";
+
+ private StringValue(String value) {
+ super(value);
+ }
+
+ /**
+ * Create a StringValue instance from an object.
+ *
+ * @param value the value to convert (String, EnumBase, or other objects).
+ * @return a StringValue instance or EMPTY if the value is null.
+ */
+ public static StringValue of(Object value) {
+ if (value == null) {
+ return EMPTY;
+ } else if (value instanceof String string) {
+ return new StringValue(string.toLowerCase().trim());
+ }
+ return EMPTY;
+ }
+
+ /**
+ * Convert a glob pattern to a regex pattern.
+ *
+ * @param glob the glob pattern to convert.
+ * @return a regex pattern equivalent to the glob.
+ */
+ public static String createRegexFromGlob(String glob) {
+ StringBuilder out = new StringBuilder();
+ for (int i = 0; i < glob.length(); ++i) {
+ final char c = glob.charAt(i);
+ switch (c) {
+ case '*':
+ out.append(".*");
+ break;
+ case '?':
+ out.append('.');
+ break;
+ case '.':
+ out.append("\\.");
+ break;
+ case '\\':
+ out.append("\\\\");
+ break;
+ case '|':
+ out.append("\\|");
+ break;
+ default:
+ out.append(c);
+ }
+ }
+ return "^" + out + "$";
+ }
+
+ /**
+ * Check if the current StringValue equals another StringValue.
+ *
+ * @param valueCompare the StringValue to compare with.
+ * @return true if both values are equal, otherwise false.
+ */
+ public boolean equals(StringValue valueCompare) {
+ return Strings.CI.equals(this.value, valueCompare.value);
+ }
+
+ /**
+ * Check if the current StringValue is not equal to another StringValue.
+ *
+ * @param valueCompare the StringValue to compare with.
+ * @return true if both values are not equal, otherwise false.
+ */
+ public boolean notEquals(StringValue valueCompare) {
+ return !equals(valueCompare);
+ }
+
+ /**
+ * Check if the current StringValue is empty or null.
+ *
+ * @return true if the current StringValue is empty or null, otherwise false.
+ */
+ public boolean isEmpty() {
+ return StringUtils.isBlank(value);
+ }
+
+ /**
+ * Check if the current StringValue is not empty.
+ *
+ * @return true if the current StringValue is not empty, otherwise false.
+ */
+ public boolean isNotEmpty() {
+ return StringUtils.isNotEmpty(value);
+ }
+
+ /**
+ * Check if the current StringValue contains another StringValue.
+ *
+ * @param valueCompares the StringValue to check.
+ * @return true if the current StringValue contains valueCompare, otherwise false.
+ */
+ public boolean contains(StringValue... valueCompares) {
+ for (StringValue valueCompare : valueCompares) {
+ if (regularExpression(valueCompare)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if the current StringValue does not contain another StringValue.
+ *
+ * @param valueCompares the StringValue to check.
+ * @return true if the current StringValue does not contain valueCompare, otherwise false.
+ */
+ public boolean doesNotContains(StringValue... valueCompares) {
+ return !contains(valueCompares);
+ }
+
+ /**
+ * Check if the current StringValue begins with another StringValue.
+ *
+ * @param valueCompares the StringValue to check.
+ * @return true if the current StringValue begins with valueCompare, otherwise false.
+ */
+ public boolean beginsWith(StringValue... valueCompares) {
+ for (StringValue valueCompare : valueCompares) {
+ if (Strings.CI.startsWith(this.value, valueCompare.getValue())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if the current StringValue ends with another StringValue.
+ *
+ * @param filterValues the StringValue to check.
+ * @return true if the current StringValue ends with valueCompare, otherwise false.
+ */
+ public boolean endsWith(StringValue... filterValues) {
+ for (StringValue valueCompare : filterValues) {
+ boolean isEndWith = Strings.CI.endsWith(this.value, valueCompare.getValue());
+ if (isEndWith) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if the current StringValue does not begin with another StringValue.
+ *
+ * @param valueCompares the StringValue to check.
+ * @return true if the current StringValue does not begin with valueCompare, otherwise false.
+ */
+ public boolean doesNotBeginWith(StringValue... valueCompares) {
+ for (StringValue valueCompare : valueCompares) {
+ boolean hasStartsWith = Strings.CI.startsWith(this.value, valueCompare.getValue());
+ if (hasStartsWith) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check if the current StringValue does not end with another StringValue.
+ *
+ * @param filterValues the StringValue to check.
+ * @return true if the current StringValue does not end with valueCompare, otherwise false.
+ */
+ public boolean doesNotEndsWith(StringValue... filterValues) {
+ for (StringValue valueCompare : filterValues) {
+ if (Strings.CI.endsWith(this.value, valueCompare.getValue())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check if the current StringValue matches a regular expression pattern.
+ *
+ * @param valueCompare the StringValue pattern to match.
+ * @return true if the current StringValue matches valueCompare, otherwise false.
+ */
+ public boolean regularExpression(StringValue valueCompare) {
+ String regex = createRegexFromGlob(valueCompare.value);
+ try {
+ // Java Escape Characters: Replace newline and tab characters with spaces
+ value = value.replaceAll("[\\n\\t\\r]", " ");
+ return value.matches(regex);
+ } catch (PatternSyntaxException patternSyntaxException) {
+ log.warn("Invalid regular expression: {}", regex);
+ return false;
+ }
+ }
+
+ /**
+ * Check if the current StringValue is in a list of StringValues.
+ *
+ * @param filterValues the list of StringValues to check.
+ * @return true if the current StringValue is in valueCompare, otherwise false.
+ */
+ public boolean in(StringValue... filterValues) {
+ if (filterValues == null) {
+ return false;
+ }
+ boolean isMatched = false;
+
+ for (StringValue filterValue : filterValues) {
+ if (equals(filterValue)) {
+ isMatched = true;
+ break;
+ }
+ }
+ return isMatched;
+ }
+
+ /**
+ * Check if the current StringValue is not in a list of StringValues.
+ *
+ * @param valueCompare the list of StringValues to check.
+ * @return true if the current StringValue is not in valueCompare, otherwise false.
+ */
+ public boolean notIn(StringValue... valueCompare) {
+ return !in(valueCompare);
+ }
+
+ public static StringValue[] split(Object object) {
+ if (object instanceof String string) {
+ return Arrays.stream(string.split("\\|")).map(StringValue::of).toArray(StringValue[]::new);
+ }
+ return null;
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/TimeValue.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/TimeValue.java
new file mode 100644
index 0000000..12e2f00
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/model/valueobject/TimeValue.java
@@ -0,0 +1,104 @@
+
+package dev.sonpx.loyalty.mcp.model.valueobject;
+
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.Optional;
+
+public class TimeValue extends BaseValue {
+
+ public static ZoneId SYSTEM_ZONE = ZoneId.systemDefault();
+
+ private static final TimeValue NULL = new TimeValue(null);
+ private static final int DEFAULT_SECONDS = 0;
+ private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
+
+ private TimeValue(LocalTime value) {
+ super(value);
+ }
+
+ /**
+ * Create a TimeValue instance from an object.
+ *
+ * @param object an object that could be a LocalTime, LocalDateTime, LocalDate, or String.
+ * @return a TimeValue instance representing the specified value, or an NULL instance if not applicable.
+ */
+ public static TimeValue of(Object object) {
+ if (object instanceof LocalTime localTime) {
+ return new TimeValue(localTime.withSecond(DEFAULT_SECONDS));
+ } else if (object instanceof LocalDateTime localDateTime) {
+ return new TimeValue(localDateTime.toLocalTime().withSecond(DEFAULT_SECONDS));
+ } else if (object instanceof LocalDate localDate) {
+ return new TimeValue(localDate.atStartOfDay().toLocalTime().withSecond(DEFAULT_SECONDS));
+ } else if (object instanceof String string) {
+ return parseString(string).orElse(NULL);
+ }
+ return NULL;
+ }
+
+ /**
+ * Parse a time string into an Optional TimeValue using a specific formatter.
+ *
+ * @param string the time string to parse.
+ * @return an Optional containing a TimeValue if parsing is successful, otherwise an empty Optional.
+ */
+ private static Optional parseString(String string) {
+ try {
+ LocalTime time = LocalTime.parse(string, TIME_FORMATTER);
+ return Optional.of(new TimeValue(time.withSecond(DEFAULT_SECONDS)));
+ } catch (DateTimeParseException e) {
+ try {
+ ZonedDateTime utcDateTime = ZonedDateTime.parse(string);
+ ZonedDateTime serverDateTime = utcDateTime.withZoneSameInstant(SYSTEM_ZONE);
+ return Optional.of(new TimeValue(serverDateTime.toLocalTime().withSecond(DEFAULT_SECONDS)));
+ } catch (DateTimeParseException ignored) {
+ return Optional.empty();
+ }
+ }
+ }
+
+ /**
+ * Check if the current TimeValue is on or before another TimeValue.
+ *
+ * @param compareValue the TimeValue to compare with.
+ * @return true if the current TimeValue is on or before compareValue, otherwise false.
+ */
+ public boolean isOnOrBefore(TimeValue compareValue) {
+ if (isNull()) {
+ return false;
+ }
+ return this.value.isBefore(compareValue.value) || this.value.equals(compareValue.value);
+ }
+
+ /**
+ * Check if the current TimeValue is on or after another TimeValue.
+ *
+ * @param compareValue the TimeValue to compare with.
+ * @return true if the current TimeValue is on or after compareValue, otherwise false.
+ */
+ public boolean isOnOrAfter(TimeValue compareValue) {
+ if (isNull()) {
+ return false;
+ }
+ return this.value.isAfter(compareValue.value) || this.value.equals(compareValue.value);
+ }
+
+ /**
+ * Check if the current TimeValue is between two other TimeValues.
+ *
+ * @param start the starting TimeValue (inclusive).
+ * @param end the ending TimeValue (inclusive).
+ * @return true if the current TimeValue is between start and end, otherwise false.
+ */
+ public boolean isBetween(TimeValue start, TimeValue end) {
+ if (isNull()) {
+ return false;
+ } else if (start.isNull()) {
+ return this.isOnOrBefore(end);
+ } else if (end.isNull()) {
+ return this.isOnOrAfter(start);
+ }
+ return this.isOnOrAfter(start) && this.isOnOrBefore(end);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/client/RewardClient.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/client/RewardClient.java
new file mode 100644
index 0000000..1c1d0e7
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/client/RewardClient.java
@@ -0,0 +1,19 @@
+package dev.sonpx.loyalty.mcp.reward.client;
+
+import dev.sonpx.loyalty.mcp.reward.criteria.CampaignCriteria;
+import dev.sonpx.loyalty.mcp.reward.model.CampaignDto;
+import java.util.List;
+import org.springframework.data.domain.Pageable;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.service.annotation.GetExchange;
+import org.springframework.web.service.annotation.HttpExchange;
+
+/**
+ * Created by SonPhung on Sunday, 19-Jul-2026
+ **/
+@HttpExchange
+public interface RewardClient {
+
+ @GetExchange("/api/campaign/csr/list")
+ ResponseEntity> getAll(CampaignCriteria criteria, Pageable pageable);
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CampaignCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CampaignCriteria.java
new file mode 100644
index 0000000..6b22f1a
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CampaignCriteria.java
@@ -0,0 +1,25 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/25
+ */
+@Data
+public class CampaignCriteria extends AbstractFwCriteria {
+
+ private StringFilter campaignId;
+ private StringFilter ownerName;
+ private StringFilter name;
+ private StringFilter description;
+ private StringFilter campaignType;
+
+ // for search text and component
+ private String[] componentColumns = {"campaign_id", "name"};
+ private String[] columns = {"description"};
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CampaignRuleCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CampaignRuleCriteria.java
new file mode 100644
index 0000000..547daf4
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CampaignRuleCriteria.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.LocalDateTimeFilter;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/31
+ */
+@Data
+public class CampaignRuleCriteria extends AbstractFwCriteria {
+
+ private StringFilter campaignId;
+ private StringFilter ruleId;
+ private StringFilter ruleName;
+ private StringFilter description;
+ private LocalDateTimeFilter effectiveFrom;
+ private LocalDateTimeFilter effectiveTo;
+ private StringFilter ruleType;
+ private StringFilter poolId;
+
+ // for search text and component
+ private String[] componentColumns = {"rule_id", "rule_name"};
+ private String[] columns = {"campaign_id", "description"};
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/ComponentCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/ComponentCriteria.java
new file mode 100644
index 0000000..34a8c23
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/ComponentCriteria.java
@@ -0,0 +1,24 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+/**
+ * @author AnhDT Created on 2025/05/22
+ */
+@Data
+public class ComponentCriteria extends AbstractFwCriteria {
+
+ private StringFilter key;
+ private StringFilter code;
+ private StringFilter name;
+
+ // for search text
+ private String[] componentColumns = {"code", "name"};
+ private String[] columns = {};
+
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CounterDefinitionCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CounterDefinitionCriteria.java
new file mode 100644
index 0000000..8e5c084
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CounterDefinitionCriteria.java
@@ -0,0 +1,35 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.LocalDateFilter;
+import dev.sonpx.loyalty.mcp.filter.LongFilter;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/31
+ */
+@Data
+public class CounterDefinitionCriteria extends AbstractFwCriteria {
+
+ private StringFilter counterId;
+ private StringFilter counterName;
+ private LocalDateFilter effectiveFrom;
+ private LocalDateFilter effectiveTo;
+ private StringFilter entity;
+ private StringFilter bucketPeriodUnit;
+ private LongFilter bucketPeriodDuration;
+ private StringFilter whatToCount;
+ private StringFilter resetType;
+ private LocalDateFilter firstStartDate;
+ private StringFilter stateCounter;
+ private StringFilter lateValuePosting;
+
+ // for search text
+ private String[] componentColumns = {"counter_id", "counter_name"};
+ private String[] columns = {"entity", "what_to_count"};
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CurrencyRateCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CurrencyRateCriteria.java
new file mode 100644
index 0000000..cf05941
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/CurrencyRateCriteria.java
@@ -0,0 +1,28 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.DoubleFilter;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+/**
+ * @author AnhDT
+ * Created on 2023/12/12
+ */
+@Data
+public class CurrencyRateCriteria extends AbstractFwCriteria {
+
+ private StringFilter pcrCode;
+ private StringFilter effectiveFrom;
+ private StringFilter effectiveTo;
+ private DoubleFilter buyRate;
+ private DoubleFilter sellRate;
+
+ // for search text
+ private String[] componentColumns = {"pcr_code"};
+ private String[] columns = {};
+
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/DeductionSequencesCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/DeductionSequencesCriteria.java
new file mode 100644
index 0000000..fae9d8c
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/DeductionSequencesCriteria.java
@@ -0,0 +1,24 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.LocalDateFilter;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+@Data
+public class DeductionSequencesCriteria extends AbstractFwCriteria {
+ private StringFilter sequenceId;
+ private StringFilter sequenceName;
+ private StringFilter description;
+ private LocalDateFilter effectiveFrom;
+ private LocalDateFilter effectiveTo;
+ private StringFilter isDefault;
+
+ // for search and component
+ private String[] componentColumns = {"sequence_id", "sequence_name"};
+ private String[] columns = {"description", "effective_from", "effective_to", "is_default"};
+
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/EventMaintenanceCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/EventMaintenanceCriteria.java
new file mode 100644
index 0000000..85a3a49
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/EventMaintenanceCriteria.java
@@ -0,0 +1,24 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/31
+ */
+@Data
+public class EventMaintenanceCriteria extends AbstractFwCriteria {
+
+ private StringFilter eventId;
+ private StringFilter description;
+
+ // for search text
+ private String[] componentColumns = {"event_id", "description"};
+ private String[] columns = {};
+
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/PoolConversionRateCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/PoolConversionRateCriteria.java
new file mode 100644
index 0000000..a1627a7
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/PoolConversionRateCriteria.java
@@ -0,0 +1,24 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+/**
+ * @author AnhDT
+ * Created on 2023/12/06
+ */
+@Data
+public class PoolConversionRateCriteria extends AbstractFwCriteria {
+
+ private StringFilter code;
+ private StringFilter description;
+
+ // for search text
+ private String[] componentColumns = {"code", "description"};
+ private String[] columns = {};
+
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/PoolDefinitionCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/PoolDefinitionCriteria.java
new file mode 100644
index 0000000..78ba836
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/PoolDefinitionCriteria.java
@@ -0,0 +1,28 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/25
+ */
+@Data
+public class PoolDefinitionCriteria extends AbstractFwCriteria {
+
+ private StringFilter poolId;
+ private StringFilter poolName;
+ private StringFilter poolType;
+ private StringFilter entityLevel;
+ private StringFilter expiryPolicy;
+ private StringFilter atgGroupId;
+
+ // for search and component
+ private String[] componentColumns = {"pool_id", "pool_name"};
+ private String[] columns = {"description"};
+
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/StatementOutputPoolCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/StatementOutputPoolCriteria.java
new file mode 100644
index 0000000..bc93501
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/StatementOutputPoolCriteria.java
@@ -0,0 +1,24 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/25
+ */
+@Data
+public class StatementOutputPoolCriteria extends AbstractFwCriteria {
+
+ private StringFilter poolId;
+ private StringFilter entityLevel;
+
+ // for search text
+ private String[] componentColumns = {"pool_id"};
+ private String[] columns = {"entity_level"};
+
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/TransactionCategoryCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/TransactionCategoryCriteria.java
new file mode 100644
index 0000000..56285f3
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/TransactionCategoryCriteria.java
@@ -0,0 +1,25 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/31
+ */
+@Data
+public class TransactionCategoryCriteria extends AbstractFwCriteria {
+
+ private StringFilter code;
+ private StringFilter name;
+ private StringFilter description;
+
+ // for search text and component
+ private String[] componentColumns = {"code", "name"};
+ private String[] columns = {};
+
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/TransactionCodeCriteria.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/TransactionCodeCriteria.java
new file mode 100644
index 0000000..52798d8
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/criteria/TransactionCodeCriteria.java
@@ -0,0 +1,26 @@
+
+package dev.sonpx.loyalty.mcp.reward.criteria;
+
+
+import dev.sonpx.loyalty.mcp.criteria.AbstractFwCriteria;
+import dev.sonpx.loyalty.mcp.filter.BooleanFilter;
+import dev.sonpx.loyalty.mcp.filter.StringFilter;
+import lombok.Data;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/25
+ */
+@Data
+public class TransactionCodeCriteria extends AbstractFwCriteria {
+
+ private StringFilter code;
+ private StringFilter description;
+ private BooleanFilter reversalInd;
+
+ // for search text and component
+ private String[] componentColumns = {"code", "description"};
+ private String[] columns = {"reversal_ind"};
+
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AlertChannel.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AlertChannel.java
new file mode 100644
index 0000000..44b6e40
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AlertChannel.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/08
+ */
+@Getter
+@RequiredArgsConstructor
+public enum AlertChannel {
+ EMAIL("E");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static AlertChannel fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AmountToUseType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AmountToUseType.java
new file mode 100644
index 0000000..c4e0405
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AmountToUseType.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/05
+ */
+@Getter
+@RequiredArgsConstructor
+public enum AmountToUseType {
+ GROSS_AMOUNT("GA"),
+ NETT_AMOUNT("NA");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static AmountToUseType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AmountToUseViewType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AmountToUseViewType.java
new file mode 100644
index 0000000..c5b10da
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AmountToUseViewType.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/03/11
+ */
+@Getter
+@RequiredArgsConstructor
+public enum AmountToUseViewType {
+ CODE(null, null),
+ ATTRIBUTE("A", "Attribute"),
+ COUNTER("C", "Counter");
+
+ private final String code;
+ private final String name;
+
+ @JsonCreator
+ public static AmountToUseViewType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AwardBasisType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AwardBasisType.java
new file mode 100644
index 0000000..8e5a7f5
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AwardBasisType.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Friday, 10-Nov-2023
+ */
+@Getter
+@RequiredArgsConstructor
+public enum AwardBasisType {
+ APPLY_EACH_TIER("AAF"),
+ APPLY_HIGHEST_TIER("AHT");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static AwardBasisType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AwardFactorType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AwardFactorType.java
new file mode 100644
index 0000000..9bceeed
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AwardFactorType.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Friday, 10-Nov-2023
+ */
+@Getter
+@RequiredArgsConstructor
+public enum AwardFactorType {
+ PERCENT("GA"),
+ POOL_UNIT("NA");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static AwardFactorType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AwardLimitType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AwardLimitType.java
new file mode 100644
index 0000000..baf3a30
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/AwardLimitType.java
@@ -0,0 +1,31 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Friday, 10-Nov-2023
+ * This sets the cap on the sum of Result from the formulas set up in Rule.
+ * If the Result from Rule exceeds this cap, then this cap is used as the Result.
+ */
+@Getter
+@RequiredArgsConstructor
+public enum AwardLimitType {
+ NO_MORE_THAN("NM"),
+ AT_LEAST("AL");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static AwardLimitType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/BaseDateType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/BaseDateType.java
new file mode 100644
index 0000000..3336380
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/BaseDateType.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/05
+ */
+@Getter
+@RequiredArgsConstructor
+public enum BaseDateType {
+ POST_DATE("PD"),
+ TRANSACTION_DATE("TD");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static BaseDateType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CampaignType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CampaignType.java
new file mode 100644
index 0000000..a841bb2
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CampaignType.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/02
+ */
+@Getter
+@RequiredArgsConstructor
+public enum CampaignType {
+ BASE("B"),
+ TACTICAL("T");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static CampaignType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CapAwardType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CapAwardType.java
new file mode 100644
index 0000000..6112186
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CapAwardType.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Friday, 10-Nov-2023
+ */
+@Getter
+@RequiredArgsConstructor
+public enum CapAwardType {
+ TRACKED_IN_COUNTER("C"),
+ PER_TRANSACTION("T");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static CapAwardType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CounterCountType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CounterCountType.java
new file mode 100644
index 0000000..2ba92fe
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CounterCountType.java
@@ -0,0 +1,32 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Wednesday, 20-Dec-2023
+ */
+@Getter
+@RequiredArgsConstructor
+public enum CounterCountType {
+ GROSS_AMOUNT("GA"),
+ NET_AMOUNT("NA"),
+ POINT("P"),
+ POINT_VALUE("PV"),
+ TRANSACTION_FREQUENCY("TF");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static CounterCountType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CounterResetType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CounterResetType.java
new file mode 100644
index 0000000..17416a2
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CounterResetType.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Wednesday, 20-Dec-2023
+ */
+@Getter
+@RequiredArgsConstructor
+public enum CounterResetType {
+ RESET_TO_REMAINDER("R"),
+ RESET_TO_ZERO("Z");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static CounterResetType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CounterUpdateType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CounterUpdateType.java
new file mode 100644
index 0000000..05cb7bc
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/CounterUpdateType.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Wednesday, 20-Dec-2023
+ */
+@Getter
+@RequiredArgsConstructor
+public enum CounterUpdateType {
+ ON_AWARD("A"),
+ ON_EXTRACT("E"),
+ NEVER("N");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static CounterUpdateType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/DeductionPriorityType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/DeductionPriorityType.java
new file mode 100644
index 0000000..dfcc446
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/DeductionPriorityType.java
@@ -0,0 +1,27 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum DeductionPriorityType {
+ START_DATE("STA"),
+ EXPIRY_DATE("EXP"),
+ CONTRIBUTOR("CON");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static DeductionPriorityType fromCode(String code) {
+ return Arrays.stream(DeductionPriorityType.values())
+ .filter(o -> o.getCode().equals(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/EventFrequencyType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/EventFrequencyType.java
new file mode 100644
index 0000000..34563c5
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/EventFrequencyType.java
@@ -0,0 +1,31 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/09
+ */
+@Getter
+@RequiredArgsConstructor
+public enum EventFrequencyType {
+ ONCE("O"),
+ MONTHLY("M"),
+ ANNUALLY("A");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static EventFrequencyType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/ExtractBlockedCard.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/ExtractBlockedCard.java
new file mode 100644
index 0000000..4b02fe9
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/ExtractBlockedCard.java
@@ -0,0 +1,28 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+// exc_blocked_card
+
+@Getter
+@RequiredArgsConstructor
+public enum ExtractBlockedCard {
+ INCLUDE("I"),
+ EXCLUDE("E");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static ExtractBlockedCard fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/ExtractNoCounter.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/ExtractNoCounter.java
new file mode 100644
index 0000000..ec94148
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/ExtractNoCounter.java
@@ -0,0 +1,26 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum ExtractNoCounter {
+ INCLUDE("I"),
+ EXCLUDE("E");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static ExtractNoCounter fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/LateValuePosting.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/LateValuePosting.java
new file mode 100644
index 0000000..60518df
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/LateValuePosting.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/08
+ */
+@Getter
+@RequiredArgsConstructor
+public enum LateValuePosting {
+ UPDATE_LATE_VALUE("L"),
+ UPDATE_CURRENT_BUCKET("C");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static LateValuePosting fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/MerchantEntityLevel.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/MerchantEntityLevel.java
new file mode 100644
index 0000000..d983fa4
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/MerchantEntityLevel.java
@@ -0,0 +1,43 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import java.util.Locale;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/15
+ */
+@Getter
+@RequiredArgsConstructor
+public enum MerchantEntityLevel {
+ CHAIN("C"),
+ CORPORATION("CO"),
+ STORE("S"),
+ TERMINAL("T");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static MerchantEntityLevel fromCode(String code) {
+ MerchantEntityLevel level = Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code) || e.name().equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ if (level != null) {
+ return level;
+ }
+ return switch (code.toUpperCase(Locale.ROOT)) {
+ case "COR" -> CORPORATION;
+ case "STO" -> STORE;
+ case "CHA" -> CHAIN;
+ case "TER" -> TERMINAL;
+ default -> null;
+ };
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/NotificationChannel.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/NotificationChannel.java
new file mode 100644
index 0000000..d97a598
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/NotificationChannel.java
@@ -0,0 +1,32 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * {@link #SMS}
+ * {@link #EMAIL}
+ * {@link #PUSH_NOTIFICATIONS}
+ */
+@Getter
+@RequiredArgsConstructor
+public enum NotificationChannel {
+ SMS("SMS"),
+ EMAIL("EMAIL"),
+ PUSH_NOTIFICATIONS("NOTIFY");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static NotificationChannel fromCode(String code) {
+ return Arrays.stream(NotificationChannel.values())
+ .filter(o -> code.equals(o.getCode()))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/PoolType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/PoolType.java
new file mode 100644
index 0000000..5259ea1
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/PoolType.java
@@ -0,0 +1,33 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/02
+ */
+@Getter
+@RequiredArgsConstructor
+public enum PoolType {
+ POINT("BPT"),
+ CASH_REBATE("CR"),
+ E_VOUCHER("GFT"),
+ MILES("MI"),
+ LUCKY_DRAW_CHANCES("LDR");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static PoolType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/PostTransactionUnderPa.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/PostTransactionUnderPa.java
new file mode 100644
index 0000000..9017845
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/PostTransactionUnderPa.java
@@ -0,0 +1,28 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum PostTransactionUnderPa {
+ BY_BASED_ON_ATG("ACA"), // PA based on ATG of Pool
+ BY_HIGHEST_SPEND("PHS"), // PA with highest spend in the past month + month to date
+ BY_LOWEST_SPEND("PL"), // PA with lowest spend in the past month + month-to-date
+ BY_MOST_RECENT("PM"); // PA with most recent customer-initiated transaction
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static PostTransactionUnderPa fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/PrecisionOfBalance.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/PrecisionOfBalance.java
new file mode 100644
index 0000000..b1ba29e
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/PrecisionOfBalance.java
@@ -0,0 +1,31 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/02
+ */
+@Getter
+@RequiredArgsConstructor
+public enum PrecisionOfBalance {
+ ZERO("0"),
+ ONE("1"),
+ TWO("2");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static PrecisionOfBalance fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equals(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RepRunSchedule.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RepRunSchedule.java
new file mode 100644
index 0000000..16eddd3
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RepRunSchedule.java
@@ -0,0 +1,36 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import java.util.List;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum RepRunSchedule {
+ DAILY("D"),
+ MONTHLY("M"),
+ ANNUALLY("A"),
+ N_DAYS_AFTER_AOD("NDAA"),
+ N_MONTHS_AFTER_AOD("NMAA"),
+ STATEMENT_CYCLE("SCD");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static RepRunSchedule fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+
+ public static boolean isRepRunSchedule(RepRunSchedule schedule) {
+ return List.of(DAILY, MONTHLY, ANNUALLY, N_DAYS_AFTER_AOD, N_MONTHS_AFTER_AOD, STATEMENT_CYCLE)
+ .contains(schedule);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RewardLimitResultType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RewardLimitResultType.java
new file mode 100644
index 0000000..76aef67
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RewardLimitResultType.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Friday, 10-Nov-2023
+ * al-capping-limit-type
+ */
+@Getter
+@RequiredArgsConstructor
+public enum RewardLimitResultType {
+ TRACKED_IN_COUNTER("C"),
+ PER_CAMPAIGN_RULE("R");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static RewardLimitResultType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RoundingType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RoundingType.java
new file mode 100644
index 0000000..e765899
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RoundingType.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Wednesday, 13-Dec-2023
+ */
+@Getter
+@RequiredArgsConstructor
+public enum RoundingType {
+ ROUND_UP("U"),
+ ROUND_DOWN("D"),
+ NEAREST("N");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static RoundingType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RuleType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RuleType.java
new file mode 100644
index 0000000..d94458f
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RuleType.java
@@ -0,0 +1,35 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Created by SonPhung on Friday, 10-Nov-2023
+ */
+@Getter
+@RequiredArgsConstructor
+public enum RuleType {
+ AWARD("AWD"),
+ REDEEM("RED"),
+ ITEM_REDEEM("IRED"),
+ ADJUSTMENT("ADJ"),
+ COUNTER_EXTRACT("CEP"),
+ REDEEM_EXTRACT("REP"),
+ TRANSACTION_EXTRACT("TEP"),
+ MARKETING_AWARD("MAWD");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static RuleType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RunSchedule.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RunSchedule.java
new file mode 100644
index 0000000..68349f1
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/RunSchedule.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum RunSchedule {
+ DAILY("D"),
+ MONTHLY("M"),
+ ANNUALLY("A"),
+ N_DAYS_AFTER_AOD("NDAA"),
+ STATEMENT_CYCLE("SCD");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static RunSchedule fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/TriggerCampaignRule.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/TriggerCampaignRule.java
new file mode 100644
index 0000000..767b8da
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/TriggerCampaignRule.java
@@ -0,0 +1,26 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public enum TriggerCampaignRule {
+ AWARD("AWD"),
+ REDEEM("RED");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static TriggerCampaignRule fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/UpdateCounterStateType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/UpdateCounterStateType.java
new file mode 100644
index 0000000..50b4415
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/UpdateCounterStateType.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/09
+ */
+@Getter
+@RequiredArgsConstructor
+public enum UpdateCounterStateType {
+ NEXT_STATE("NS"),
+ PREVIOUS_STATE("PS");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static UpdateCounterStateType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityEntity.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityEntity.java
new file mode 100644
index 0000000..f94ee52
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityEntity.java
@@ -0,0 +1,31 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/02
+ */
+@Getter
+@RequiredArgsConstructor
+public enum VelocityEntity {
+ CARD("CA"),
+ CUSTOMER("CU"),
+ ACCOUNT("AC");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static VelocityEntity fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityPeriod.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityPeriod.java
new file mode 100644
index 0000000..95ec05f
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityPeriod.java
@@ -0,0 +1,33 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/02
+ */
+@Getter
+@RequiredArgsConstructor
+public enum VelocityPeriod {
+ PER_QUARTER("Q"),
+ PER_WEEK("W"),
+ PER_YEAR("Y"),
+ PER_DAY("D"),
+ PER_MONTH("M");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static VelocityPeriod fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityTransactionType.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityTransactionType.java
new file mode 100644
index 0000000..a78c766
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityTransactionType.java
@@ -0,0 +1,31 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/02
+ */
+@Getter
+@RequiredArgsConstructor
+public enum VelocityTransactionType {
+ AWARD("AWD"),
+ REDEEM("RED"),
+ ADJUST("ADJ");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static VelocityTransactionType fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityUnit.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityUnit.java
new file mode 100644
index 0000000..a168248
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/enums/VelocityUnit.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/02
+ */
+@Getter
+@RequiredArgsConstructor
+public enum VelocityUnit {
+ POOL_UNITS("PU"),
+ TRANSACTIONS("TXN");
+
+ @JsonValue
+ private final String code;
+
+ @JsonCreator
+ public static VelocityUnit fromCode(String code) {
+ return Arrays.stream(values())
+ .filter(e -> e.code.equalsIgnoreCase(code))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/AlertManagementDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/AlertManagementDto.java
new file mode 100644
index 0000000..4f5b0b1
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/AlertManagementDto.java
@@ -0,0 +1,27 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/12/20
+ */
+@Setter
+@Getter
+public class AlertManagementDto extends FwDto {
+
+ @NotBlank
+ @Size(min = 1, max = 10)
+ private String alertId;
+
+ @NotBlank
+ @Size(min = 1, max = 30)
+ private String name;
+
+ @Size(min = 1, max = 50)
+ private String description;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/AmountToUseViewDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/AmountToUseViewDto.java
new file mode 100644
index 0000000..6bc6260
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/AmountToUseViewDto.java
@@ -0,0 +1,13 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/18
+ */
+@Getter
+@Setter
+public class AmountToUseViewDto extends ComponentDto {}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignAwardLimitDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignAwardLimitDto.java
new file mode 100644
index 0000000..09f83ca
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignAwardLimitDto.java
@@ -0,0 +1,34 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import dev.sonpx.loyalty.mcp.reward.enums.AwardLimitType;
+import dev.sonpx.loyalty.mcp.reward.enums.RewardLimitResultType;
+import jakarta.validation.constraints.Size;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Thursday, 09-Nov-2023
+ */
+@Getter
+@Setter
+public class CampaignAwardLimitDto extends FwDto {
+
+ private AwardLimitType limitType;
+
+ private Double limitByValue;
+
+ private ReferenceData limitByAttribute;
+
+ private RewardLimitResultType limitResultType;
+
+ private ReferenceData counterId;
+
+ @Size(max = 20)
+ private String alertId;
+
+ @Size(max = 50)
+ private String alertRecipientGroup;
+
+ private Double alertCounterReaches;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignContributorDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignContributorDto.java
new file mode 100644
index 0000000..9de9049
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignContributorDto.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.DecimalMax;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Thursday, 09-Nov-2023
+ */
+@Getter
+@Setter
+public class CampaignContributorDto extends FwDto {
+
+ private ReferenceData chainId;
+
+ private ReferenceData corporationId;
+
+ private ReferenceData storeId;
+
+ @NotNull
+ @DecimalMax("100.00")
+ @DecimalMin("0.01")
+ private Double contributorPercent;
+
+ private Boolean absorbRemainder;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignCriteriaDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignCriteriaDto.java
new file mode 100644
index 0000000..7419e02
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignCriteriaDto.java
@@ -0,0 +1,17 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Thursday, 09-Nov-2023
+ */
+@Getter
+@Setter
+public class CampaignCriteriaDto extends FwDto {
+
+ @NotBlank
+ private String criteria;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignDto.java
new file mode 100644
index 0000000..2c91f24
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignDto.java
@@ -0,0 +1,40 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import dev.sonpx.loyalty.mcp.reward.enums.CampaignType;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import java.time.LocalDate;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CampaignDto extends FwDto {
+
+ @NotBlank
+ @Size(min = 1, max = 10)
+ private String campaignId;
+
+ @Size(max = 50)
+ private String ownerName;
+
+ @NotBlank
+ @Size(min = 1, max = 50)
+ private String name;
+
+ @Size(max = 500)
+ private String description;
+
+ private CampaignType campaignType;
+
+ private Long noOfCustomerTarget;
+
+ private Double targetAtv;
+
+ private LocalDate effectiveFrom;
+
+ private LocalDate effectiveTo;
+
+ private Integer numOfRule;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaEightDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaEightDto.java
new file mode 100644
index 0000000..625f528
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaEightDto.java
@@ -0,0 +1,54 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import dev.sonpx.loyalty.mcp.enums.ExpiryPolicy;
+import dev.sonpx.loyalty.mcp.model.AttributeData;
+import jakarta.validation.constraints.NotNull;
+import java.time.LocalDate;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Thursday, 09-Nov-2023
+ */
+@Getter
+@Setter
+public class CampaignFormulaEightDto extends FwDto {
+
+ private ReferenceData attrGroup;
+
+ /**
+ * criteria/condition
+ */
+ @NotNull
+ private AttributeData attributeId;
+
+ private String attributeType;
+
+ private String attrVal; // priority
+
+ private String andAttrVal; // used types: number, date
+
+ /**
+ * updated values
+ */
+ private AttributeData setAttributeId;
+
+ private String setAttrValue;
+
+ /**
+ * expiring
+ */
+ private LocalDate fixedExpiryDate;
+
+ private ExpiryPolicy expiryPeriodUnit;
+
+ private Long expiredParam;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Integer dayOfMonth;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Integer monthOfYear;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaElevenDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaElevenDto.java
new file mode 100644
index 0000000..b87be16
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaElevenDto.java
@@ -0,0 +1,30 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import dev.sonpx.loyalty.mcp.reward.enums.AwardFactorType;
+import jakarta.validation.constraints.DecimalMax;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * F11
+ */
+@Getter
+@Setter
+public class CampaignFormulaElevenDto extends FwDto {
+
+ @NotNull
+ private ReferenceData segmentId;
+
+ private String operator;
+
+ @NotNull
+ private AwardFactorType factorType;
+
+ @NotNull
+ @Min(0)
+ @DecimalMax(value = "99999999999999.99")
+ private Double factorValue;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaFiveDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaFiveDto.java
new file mode 100644
index 0000000..1d27ffa
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaFiveDto.java
@@ -0,0 +1,20 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Thursday, 09-Nov-2023
+ */
+@Getter
+@Setter
+public class CampaignFormulaFiveDto extends FwDto {
+
+ @NotNull
+ private Double multiply;
+
+ @NotNull
+ private ReferenceData counterId;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaFourDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaFourDto.java
new file mode 100644
index 0000000..c32a199
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaFourDto.java
@@ -0,0 +1,27 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+
+import dev.sonpx.loyalty.mcp.reward.enums.AwardBasisType;
+import dev.sonpx.loyalty.mcp.reward.enums.AwardFactorType;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotEmpty;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Thursday, 09-Nov-2023
+ */
+@Getter
+@Setter
+public class CampaignFormulaFourDto extends FwDto {
+
+ private AwardFactorType factorType;
+
+ private AwardBasisType basisType;
+
+ @Valid
+ @NotEmpty
+ private List tiers;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaFourTierDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaFourTierDto.java
new file mode 100644
index 0000000..8503b75
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaFourTierDto.java
@@ -0,0 +1,50 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.DecimalMax;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Positive;
+import lombok.*;
+
+/**
+ * Created by AnhNt on Friday, 24-Nov-2023
+ */
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class CampaignFormulaFourTierDto {
+
+ @Min(1)
+ private int tier;
+
+ @NotNull
+ @Min(0)
+ @DecimalMax(value = "99999999999999.99")
+ private Double startTier;
+
+ @NotNull
+ @Min(0)
+ @DecimalMax(value = "99999999999999.99")
+ private Double endTier;
+
+ @NotNull
+ @Min(0)
+ @DecimalMax(value = "99999999999999.99")
+ private Double awardFactor;
+
+ // AFTER
+ @Positive
+ @DecimalMax(value = "99999999999999.99")
+ private Double startTierAfter;
+
+ @Positive
+ @DecimalMax(value = "99999999999999.99")
+ private Double endTierAfter;
+
+ @Positive
+ @DecimalMax(value = "99999999999999.99")
+ private Double awardFactorAfter;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaOneDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaOneDto.java
new file mode 100644
index 0000000..7d9be42
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaOneDto.java
@@ -0,0 +1,31 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.DecimalMax;
+import jakarta.validation.constraints.Positive;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Thursday, 09-Nov-2023
+ */
+@Getter
+@Setter
+public class CampaignFormulaOneDto extends FwDto {
+
+ @Positive
+ @DecimalMax(value = "99999999999999.99")
+ private Double awardPerTxnAmt;
+
+ @Positive
+ @DecimalMax(value = "99999999999999.99")
+ private Double txnAmt;
+
+ @Positive
+ @DecimalMax(value = "99999999999999.99")
+ private Double awardPerTxnAmtAfter;
+
+ @Positive
+ @DecimalMax(value = "99999999999999.99")
+ private Double txnAmtAfter;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaSettingDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaSettingDto.java
new file mode 100644
index 0000000..83fa98e
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaSettingDto.java
@@ -0,0 +1,34 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+
+import dev.sonpx.loyalty.mcp.reward.enums.CapAwardType;
+import dev.sonpx.loyalty.mcp.reward.enums.RoundingType;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Thursday, 09-Nov-2023
+ */
+@Getter
+@Setter
+public class CampaignFormulaSettingDto extends FwDto {
+
+ private String ruleId;
+
+ private Long ruleRecordNo;
+
+ private ReferenceData amountToUse;
+
+ private String nParam;
+
+ private Double capAwardValue;
+
+ private CapAwardType capAwardType;
+
+ private ReferenceData capAwardCounterId;
+
+ private Boolean applyCapValueAfter;
+
+ private RoundingType roundingType;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaSixDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaSixDto.java
new file mode 100644
index 0000000..627a8a1
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaSixDto.java
@@ -0,0 +1,28 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import dev.sonpx.loyalty.mcp.reward.enums.AwardFactorType;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Thursday, 09-Nov-2023
+ */
+@Getter
+@Setter
+public class CampaignFormulaSixDto extends FwDto {
+
+ @NotNull
+ private AwardFactorType factorType;
+
+ @NotNull
+ private ReferenceData decideTierBase;
+
+ @Valid
+ @NotEmpty
+ private List tiers;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaSixTierDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaSixTierDto.java
new file mode 100644
index 0000000..865e4dc
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaSixTierDto.java
@@ -0,0 +1,37 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.DecimalMax;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import lombok.*;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/09
+ */
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class CampaignFormulaSixTierDto {
+
+ @Min(1)
+ private int tier;
+
+ @NotNull
+ @Min(0)
+ @DecimalMax(value = "99999999999999.99")
+ private Double startTier;
+
+ @NotNull
+ @Min(0)
+ @DecimalMax(value = "99999999999999.99")
+ private Double endTier;
+
+ @NotNull
+ @Min(0)
+ @DecimalMax(value = "99999999999999.99")
+ private Double awardFactor;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaTenDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaTenDto.java
new file mode 100644
index 0000000..91fc718
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaTenDto.java
@@ -0,0 +1,37 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import dev.sonpx.loyalty.mcp.model.AttributeData;
+import dev.sonpx.loyalty.mcp.reward.enums.AwardFactorType;
+import jakarta.validation.constraints.DecimalMax;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * F10
+ */
+@Getter
+@Setter
+public class CampaignFormulaTenDto extends FwDto {
+
+ @NotNull
+ private AttributeData attributeId;
+
+ private String attributeType;
+
+ private String operator;
+
+ private String attributeValue;
+
+ private String attributeValueAnd;
+
+ @NotNull
+ private AwardFactorType factorType;
+
+ @NotNull
+ @Min(0)
+ @DecimalMax(value = "99999999999999.99")
+ private Double factorValue;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaTwoDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaTwoDto.java
new file mode 100644
index 0000000..e21ffff
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignFormulaTwoDto.java
@@ -0,0 +1,17 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.Positive;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Thursday, 09-Nov-2023
+ */
+@Getter
+@Setter
+public class CampaignFormulaTwoDto extends FwDto {
+
+ @Positive
+ private Double fixedAmt;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleByPoolDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleByPoolDto.java
new file mode 100644
index 0000000..4233ff7
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleByPoolDto.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import java.time.LocalDateTime;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2024/03/15
+ */
+@Getter
+@Setter
+@Builder
+public class CampaignRuleByPoolDto {
+
+ private String poolId;
+
+ private ReferenceData campaign;
+
+ private ReferenceData rule;
+
+ private ReferenceData transactionCode;
+
+ private LocalDateTime effectiveFrom;
+
+ private LocalDateTime effectiveTo;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleByTxnCodeDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleByTxnCodeDto.java
new file mode 100644
index 0000000..8fe1467
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleByTxnCodeDto.java
@@ -0,0 +1,16 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CampaignRuleByTxnCodeDto {
+
+ private String ruleId;
+
+ private String ruleName;
+
+ private long executionSeq;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleDto.java
new file mode 100644
index 0000000..1d4cbb3
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleDto.java
@@ -0,0 +1,163 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import dev.sonpx.loyalty.mcp.enums.ExpiryPolicy;
+import dev.sonpx.loyalty.mcp.reward.enums.BaseDateType;
+import dev.sonpx.loyalty.mcp.reward.enums.NotificationChannel;
+import dev.sonpx.loyalty.mcp.reward.enums.RuleType;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Monday, 13-Mon-2023
+ */
+@Getter
+@Setter
+public class CampaignRuleDto extends FwDto {
+
+ /**
+ * General Rule Infomation
+ */
+ @NotNull
+ private ReferenceData campaignId;
+
+ @NotBlank
+ @Size(min = 1, max = 10)
+ private String ruleId;
+
+ @NotBlank
+ @Size(min = 1, max = 100)
+ private String ruleName;
+
+ private RuleType ruleType;
+
+ @Size(max = 500)
+ private String description;
+
+ private LocalDateTime effectiveFrom;
+
+ private LocalDateTime effectiveTo;
+
+ private BaseDateType effectivePeriodIsBase;
+
+ private ReferenceData messageTemplateId;
+
+ private Boolean stopIfCriteriaMet;
+
+ private Boolean notUpdatePool;
+
+ @Valid
+ private List campaignTcLinkages;
+
+ /**
+ * Rule Criteria
+ */
+ @Valid
+ private CampaignCriteriaDto campaignCriteria;
+
+ /**
+ * Reward Setting - AWD/RED
+ */
+ private ReferenceData poolId;
+
+ private ReferenceData subPoolId;
+
+ private ExpiryPolicy expiryPolicy;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Integer expiryPolicyParam;
+
+ private LocalDate fixedDate;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Integer dayOfMonth;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Integer monthOfYear;
+
+ private ReferenceData itemCode;
+
+ // Aplly the first criterion satified in Formula 10
+ private Boolean attrApplyFirstFlag;
+
+ // Aplly the first criterion satified in Formula 11
+ private Boolean segApplyFirstFlag;
+
+ @Valid
+ private CampaignFormulaSettingDto campaignFormulaSetting;
+
+ @Valid
+ private List campaignAwardLimits;
+
+ @Valid
+ private CampaignFormulaOneDto campaignFormulaOne;
+
+ @Valid
+ private CampaignFormulaTwoDto campaignFormulaTwo;
+
+ @Valid
+ private CampaignFormulaFourDto campaignFormulaFour;
+
+ @Valid
+ private List campaignFormulaFives;
+
+ @Valid
+ private CampaignFormulaSixDto campaignFormulaSix;
+
+ @Valid
+ private List campaignFormulaEights;
+
+ @Valid
+ private List campaignFormulaTens;
+
+ @Valid
+ private List campaignFormulaElevens;
+
+ @Valid
+ private List campaignContributors;
+
+ private List formulaSequence;
+
+ /**
+ * Redemption Extract Rule Type
+ */
+ private RedemptionExtractRequestDto redemptionExtract;
+
+ /**
+ * Counter Extract Rule Type
+ */
+ @Valid
+ private CounterExtractRequestDto counterExtractRequest;
+
+ /**
+ * Marketing Reward Rule Type
+ */
+ @Valid
+ private MarketingRewardRequestDto marketingRewardRequest;
+
+ @Valid
+ private CampaignRuleScheduleDto campaignRuleSchedule;
+
+ /**
+ * Notification Info
+ */
+ private NotificationChannel channel;
+
+ @Valid
+ private RewardContentSmsDto rewardContentSms;
+
+ @Valid
+ private RewardContentEmailDto rewardContentEmail;
+
+ @Valid
+ private RewardContentNotificationDto rewardContentNotification;
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleScheduleDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleScheduleDto.java
new file mode 100644
index 0000000..a6a0927
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignRuleScheduleDto.java
@@ -0,0 +1,44 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import dev.sonpx.loyalty.mcp.enums.schedule.*;
+import jakarta.validation.constraints.Positive;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CampaignRuleScheduleDto extends FwDto {
+
+ private String ruleId;
+
+ private TriggerMethod triggerMethod;
+
+ private ScheduleRecurrenceType scheduleType;
+
+ private PeriodicType periodicType;
+
+ @Positive
+ private Integer repeatPeriod;
+
+ private LocalDate fixedDate;
+
+ private ScheduleMonthType scheduleMonthType;
+
+ private List scheduleDayOfWeek;
+
+ private WeekOfMonth scheduleWeekOfMonth;
+
+ private List scheduleDayOfMonth;
+
+ private Boolean lastDayOfMonth;
+
+ private List scheduleMonthOfYear;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm")
+ private LocalTime timeExecution;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignTcLinkageDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignTcLinkageDto.java
new file mode 100644
index 0000000..64e07ee
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CampaignTcLinkageDto.java
@@ -0,0 +1,20 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Wednesday, 08-Nov-2023
+ */
+@Getter
+@Setter
+public class CampaignTcLinkageDto extends FwDto {
+
+ @NotNull
+ private ReferenceData transactionCode;
+
+ @NotNull
+ private long executionSeq;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/ComponentDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/ComponentDto.java
new file mode 100644
index 0000000..fe8ce5c
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/ComponentDto.java
@@ -0,0 +1,20 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2025/10/28
+ */
+@Getter
+@Setter
+public class ComponentDto {
+
+ protected String key;
+
+ protected String code;
+
+ protected String name;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterCriteriaDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterCriteriaDto.java
new file mode 100644
index 0000000..6cd0ce7
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterCriteriaDto.java
@@ -0,0 +1,16 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CounterCriteriaDto {
+
+ private String key;
+
+ private String code;
+
+ private String name;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterDefinitionDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterDefinitionDto.java
new file mode 100644
index 0000000..1d1f3d6
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterDefinitionDto.java
@@ -0,0 +1,73 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+
+
+
+import dev.sonpx.loyalty.mcp.enums.CounterEntity;
+import dev.sonpx.loyalty.mcp.enums.CounterPeriod;
+import dev.sonpx.loyalty.mcp.reward.enums.CounterCountType;
+import dev.sonpx.loyalty.mcp.reward.enums.CounterResetType;
+import dev.sonpx.loyalty.mcp.reward.enums.CounterUpdateType;
+import dev.sonpx.loyalty.mcp.reward.enums.LateValuePosting;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import java.time.LocalDate;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/31
+ */
+@Getter
+@Setter
+public class CounterDefinitionDto extends FwDto {
+
+ @NotBlank
+ @Size(max = 10)
+ private String counterId;
+
+ @NotBlank
+ @Size(max = 50)
+ private String counterName;
+
+ @Size(max = 200)
+ private String description;
+
+ @NotNull
+ private LocalDate effectiveFrom;
+
+ @NotNull
+ private LocalDate effectiveTo;
+
+ @NotNull
+ private CounterEntity entity; // counter level
+
+ @NotNull
+ private CounterPeriod bucketPeriodUnit; // counter period
+
+ private LocalDate bucketEndDate; // fixedDate;
+
+ private Integer bucketPeriodDuration; // parameterForPeriod;
+
+ @NotNull
+ private CounterCountType whatToCount; // counts;
+
+ @NotNull
+ private CounterResetType resetType;
+
+ @NotNull
+ private Double resetValue;
+
+ private Boolean firstDateType;
+
+ private LocalDate firstStartDate;
+
+ @NotNull
+ private CounterUpdateType updateStateWhen; // stateCounter;
+
+ @NotNull
+ private LateValuePosting lateValuePosting;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterExtractRequestDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterExtractRequestDto.java
new file mode 100644
index 0000000..2957d32
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterExtractRequestDto.java
@@ -0,0 +1,51 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+
+
+import dev.sonpx.loyalty.mcp.enums.CounterBucket;
+import dev.sonpx.loyalty.mcp.reward.enums.ExtractBlockedCard;
+import dev.sonpx.loyalty.mcp.reward.enums.ExtractNoCounter;
+import dev.sonpx.loyalty.mcp.reward.enums.PostTransactionUnderPa;
+import dev.sonpx.loyalty.mcp.reward.enums.TriggerCampaignRule;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CounterExtractRequestDto extends FwDto {
+
+ @NotNull
+ private ReferenceData store;
+
+ @NotNull
+ private ReferenceData counterExtract;
+
+ @NotNull
+ public CounterBucket counterBucket;
+
+ private String nParam;
+
+// @NotNull
+ private TriggerCampaignRule triggerCampaignRule;
+
+ @NotNull
+ private ReferenceData transactionCode;
+
+ private ReferenceData adjustTransactionCode;
+
+ private ReferenceData adjustTransactionReason;
+
+ @Size(max = 255)
+ private String adjustTransactionDescription;
+
+ private PostTransactionUnderPa postTransactionUnderPa;
+
+ private ExtractBlockedCard includeAcctWithBlockedCard;
+
+ private ExtractNoCounter includeAcctNoCounter;
+
+ private Integer executeSequenceNumber;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterStockDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterStockDto.java
new file mode 100644
index 0000000..5fbf147
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CounterStockDto.java
@@ -0,0 +1,35 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import java.time.LocalDateTime;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/12/20
+ */
+@Setter
+@Getter
+public class CounterStockDto extends FwDto {
+
+ private String counterId;
+
+ private String entityLevel;
+
+ private String entityValue;
+
+ private Double counterValue;
+
+ private LocalDateTime firstStartDate;
+
+ private LocalDateTime bucketStartDate;
+
+ private LocalDateTime bucketEndDate;
+
+ private Integer bucketNumeric;
+
+ private Double lateCounterValue;
+
+ private String state;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CurrencyRateDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CurrencyRateDto.java
new file mode 100644
index 0000000..89758b8
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/CurrencyRateDto.java
@@ -0,0 +1,34 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/12/12
+ */
+@Setter
+@Getter
+public class CurrencyRateDto extends FwDto {
+
+ @NotNull
+ private ReferenceData pcrCode;
+
+ private String currencyRateId = "0"; // default value
+
+ @NotNull
+ private LocalDate effectiveFrom;
+
+ @NotNull
+ private LocalDate effectiveTo;
+
+ @NotNull
+ private BigDecimal buyRate;
+
+ @NotNull
+ private BigDecimal sellRate;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/DecideTierViewDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/DecideTierViewDto.java
new file mode 100644
index 0000000..b186bcd
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/DecideTierViewDto.java
@@ -0,0 +1,9 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class DecideTierViewDto extends ComponentDto {}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/DeductionSequencesDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/DeductionSequencesDto.java
new file mode 100644
index 0000000..91a2c6d
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/DeductionSequencesDto.java
@@ -0,0 +1,34 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import java.time.LocalDate;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class DeductionSequencesDto extends FwDto {
+ @NotBlank
+ @Size(min = 1, max = 50)
+ private String sequenceId;
+
+ @NotBlank
+ @Size(max = 100)
+ private String sequenceName;
+
+ private String description;
+
+ @NotNull
+ private LocalDate effectiveFrom;
+
+ @NotNull
+ private LocalDate effectiveTo;
+
+ @NotNull
+ private Boolean isDefault;
+
+ private String sortCriteria;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/EventMaintenanceDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/EventMaintenanceDto.java
new file mode 100644
index 0000000..13bcaa3
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/EventMaintenanceDto.java
@@ -0,0 +1,32 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+
+import dev.sonpx.loyalty.mcp.reward.enums.EventFrequencyType;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.time.LocalDate;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/31
+ */
+@Getter
+@Setter
+public class EventMaintenanceDto extends FwDto {
+
+ @NotBlank
+ private String eventId;
+
+ @NotBlank
+ private String description;
+
+ private EventFrequencyType frequency;
+
+ @NotNull
+ private LocalDate occursNext;
+
+ private LocalDate effectiveUpTo;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/FwDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/FwDto.java
new file mode 100644
index 0000000..e71c3d9
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/FwDto.java
@@ -0,0 +1,41 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.time.Instant;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Created by SonPhung on Wednesday, 18-Oct-2023
+ */
+@Getter
+@Setter
+public abstract class FwDto implements Serializable {
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ protected Long recordNo;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ protected String status;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ protected String lastUpdateBy;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ protected Instant lastUpdateDate;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ protected String lastApproveBy;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ protected Instant lastApproveDate;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ protected String lastUpdateByName;
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ protected String lastApproveByName;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/ImageReferenceDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/ImageReferenceDto.java
new file mode 100644
index 0000000..2313625
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/ImageReferenceDto.java
@@ -0,0 +1,16 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class ImageReferenceDto {
+
+ private String imageSource;
+
+ private String imageId;
+
+ private String imageUrl;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/LinkedPoolDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/LinkedPoolDto.java
new file mode 100644
index 0000000..755fd0e
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/LinkedPoolDto.java
@@ -0,0 +1,24 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import java.time.LocalDateTime;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/12/28
+ */
+@Setter
+@Getter
+@AllArgsConstructor
+public class LinkedPoolDto {
+
+ private String poolId;
+ private String poolName;
+ private String ruleId;
+ private String ruleName;
+ private LocalDateTime effectiveFrom;
+ private LocalDateTime effectiveTo;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/MarketingRewardRequestDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/MarketingRewardRequestDto.java
new file mode 100644
index 0000000..0b61785
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/MarketingRewardRequestDto.java
@@ -0,0 +1,25 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2024/09/23
+ */
+@Getter
+@Setter
+public class MarketingRewardRequestDto extends FwDto {
+
+ private String ruleId;
+
+ private ReferenceData poolId;
+
+ @NotNull
+ private ReferenceData awardTransactionCode;
+
+ @NotNull
+ private ReferenceData storeId;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/MessageTemplateDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/MessageTemplateDto.java
new file mode 100644
index 0000000..f84e0d9
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/MessageTemplateDto.java
@@ -0,0 +1,31 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import java.time.LocalDate;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/03
+ */
+@Setter
+@Getter
+public class MessageTemplateDto extends FwDto {
+
+ @NotBlank
+ @Size(min = 1, max = 10)
+ private String messageId;
+
+ @NotBlank
+ private String description;
+
+ @NotNull
+ private LocalDate effectiveFrom;
+
+ @NotNull
+ private LocalDate effectiveTo;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/MqPoolConfigDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/MqPoolConfigDto.java
new file mode 100644
index 0000000..66f7d75
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/MqPoolConfigDto.java
@@ -0,0 +1,26 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/31
+ */
+@Getter
+@Setter
+public class MqPoolConfigDto extends FwDto {
+
+ @NotBlank
+ private String messageType;
+
+ @NotBlank
+ private String description;
+
+ @NotBlank
+ private String cbPoolId;
+
+ private String uniPoolId;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PaTypeExpiryDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PaTypeExpiryDto.java
new file mode 100644
index 0000000..f18fe50
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PaTypeExpiryDto.java
@@ -0,0 +1,34 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import dev.sonpx.loyalty.mcp.enums.ExpiryPolicy;
+import jakarta.validation.constraints.NotNull;
+import java.time.LocalDate;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * PhuDao created on 16/10/2023
+ */
+@Getter
+@Setter
+public class PaTypeExpiryDto extends FwDto {
+
+ private Long poolRecordNo;
+
+ private String poolId;
+
+ @NotNull
+ private ReferenceData productAccountLevel;
+
+ @NotNull
+ private ReferenceData productAccountType;
+
+ private ExpiryPolicy expiryPolicy;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Integer expiryPolicyParam;
+
+ private LocalDate fixedDate;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PoolByEntityLevelRequestDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PoolByEntityLevelRequestDto.java
new file mode 100644
index 0000000..d598e2c
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PoolByEntityLevelRequestDto.java
@@ -0,0 +1,27 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import dev.sonpx.loyalty.mcp.enums.EntityLevel;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.Set;
+import lombok.*;
+
+/**
+ * @author AnhDT
+ * Created on 2024/03/07
+ */
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PoolByEntityLevelRequestDto implements Serializable {
+
+ @NotEmpty
+ private Set poolSet;
+
+ @NotNull
+ private EntityLevel entityLevel;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PoolConversionRateDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PoolConversionRateDto.java
new file mode 100644
index 0000000..89961af
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PoolConversionRateDto.java
@@ -0,0 +1,24 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/12/06
+ */
+@Setter
+@Getter
+public class PoolConversionRateDto extends FwDto {
+
+ @NotBlank
+ @Size(min = 1, max = 5)
+ private String code;
+
+ @NotBlank
+ @Size(max = 30)
+ private String description;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PoolDefinitionDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PoolDefinitionDto.java
new file mode 100644
index 0000000..2a26379
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/PoolDefinitionDto.java
@@ -0,0 +1,70 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import dev.sonpx.loyalty.mcp.enums.EntityLevel;
+import dev.sonpx.loyalty.mcp.enums.ExpiryPolicy;
+import dev.sonpx.loyalty.mcp.reward.enums.PoolType;
+import dev.sonpx.loyalty.mcp.reward.enums.PrecisionOfBalance;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import java.time.LocalDate;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/23
+ */
+@Getter
+@Setter
+public class PoolDefinitionDto extends FwDto {
+
+ @NotBlank
+ private String poolId;
+
+ @NotBlank
+ private String poolName;
+
+ private String description;
+
+ private PoolType poolType;
+
+ private ExpiryPolicy expiryPolicy;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Integer expiryPolicyParam;
+
+ private LocalDate fixedDate;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Integer ripeningPeriod;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Integer dayOfMonth;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Integer monthOfYear;
+
+ private ReferenceData pcrCode;
+
+ private Boolean allowNegativeBalance;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private PrecisionOfBalance precisionOfBalance;
+
+ private ReferenceData atgGroupId;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Integer gracePeriod;
+
+ private EntityLevel entityLevel;
+
+ // submodules
+ @Valid
+ private List paTypeExpiries;
+
+ @Valid
+ private List velocityControls;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RecipientGroupDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RecipientGroupDto.java
new file mode 100644
index 0000000..9db3a2a
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RecipientGroupDto.java
@@ -0,0 +1,27 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+
+import dev.sonpx.loyalty.mcp.reward.enums.AlertChannel;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2024/01/08
+ */
+@Setter
+@Getter
+public class RecipientGroupDto extends FwDto {
+
+ @NotBlank
+ private String recipientGroupId;
+
+ @NotBlank
+ private String name;
+
+ private AlertChannel channel;
+
+ private String recipientIds;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RedemptionExtractRequestDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RedemptionExtractRequestDto.java
new file mode 100644
index 0000000..376a413
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RedemptionExtractRequestDto.java
@@ -0,0 +1,38 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.Size;
+import java.math.BigDecimal;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/12/20
+ */
+@Setter
+@Getter
+public class RedemptionExtractRequestDto extends FwDto {
+
+ private ReferenceData poolId;
+
+ private BigDecimal minPoolBalance;
+
+ private ReferenceData redTxnCode;
+
+ @Size(max = 150)
+ private String redTxnDesc;
+
+ private ReferenceData storeId;
+
+ private ReferenceData adjTxnCode;
+
+ private ReferenceData adjTxnReason;
+
+ @Size(max = 100)
+ private String adjTxnDesc;
+
+ private String outputRedemption;
+
+ private boolean triggerCampaignRule;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/ReferenceData.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/ReferenceData.java
new file mode 100644
index 0000000..278541c
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/ReferenceData.java
@@ -0,0 +1,75 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * Created by tuanngo on Tue, 2025-04-16
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+public class ReferenceData implements Serializable {
+
+ protected String code;
+ protected String description;
+ protected boolean notFound;
+ protected String recordStatus;
+ protected Map attributes = new HashMap<>();
+
+ public ReferenceData(String code) {
+ this.code = code;
+ }
+
+ public ReferenceData(String code, String description) {
+ this.code = code;
+ this.description = description;
+ this.notFound = false;
+ }
+
+ public ReferenceData(String code, String description, Boolean notFound) {
+ this.code = code;
+ this.description = description;
+ this.notFound = notFound;
+ }
+
+ public ReferenceData(String code, String description, boolean notFound, String recordStatus) {
+ this.code = code;
+ this.description = description;
+ this.notFound = notFound;
+ this.recordStatus = recordStatus;
+ }
+
+ public ReferenceData(String code, String description, Map attributes) {
+ this.code = code;
+ this.description = description;
+ this.attributes = attributes;
+ }
+
+ public void addAttribute(String key, Object value) {
+ this.attributes.put(key, value);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ ReferenceData that = (ReferenceData) o;
+ return Objects.equals(code, that.code) && Objects.equals(description, that.description);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(code, description);
+ }
+
+ @Override
+ public String toString() {
+ return "ReferenceData{" + "code='" + code + '\'' + ", notFound=" + notFound + '}';
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardContentEmailDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardContentEmailDto.java
new file mode 100644
index 0000000..dc51d51
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardContentEmailDto.java
@@ -0,0 +1,34 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2024/10/21
+ */
+@Getter
+@Setter
+public class RewardContentEmailDto extends FwDto {
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Long ruleRecordNo;
+
+ private String ruleId;
+
+ private String sender;
+
+ private ReferenceData messageId;
+
+ private String subject;
+
+ private String body;
+
+ private String design;
+
+ private String metadata;
+
+ private String attachments;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardContentNotificationDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardContentNotificationDto.java
new file mode 100644
index 0000000..455fdb3
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardContentNotificationDto.java
@@ -0,0 +1,62 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2024/10/21
+ */
+@Getter
+@Setter
+public class RewardContentNotificationDto extends FwDto {
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Long ruleRecordNo;
+
+ private String ruleId;
+
+ private ReferenceData messageId;
+
+ private String messageType;
+
+ private String notificationContentId;
+
+ private String languageCode;
+
+ private String title;
+
+ private String shortContent;
+
+ private String content;
+
+ private ReferenceData navigationType;
+
+ private String link;
+
+ private ReferenceData targetScreen;
+
+ private ReferenceData poolId;
+
+ private ReferenceData offerGroup;
+
+ private ReferenceData categoryId;
+
+ private ReferenceData referenceNo;
+
+ private ReferenceData campaignId;
+
+ private ReferenceData itemCode;
+
+ private ReferenceData notificationType;
+
+ private Boolean richMedia;
+
+ private ImageReferenceDto avatar;
+
+ private List relatedButtons;
+
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardContentSmsDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardContentSmsDto.java
new file mode 100644
index 0000000..94a0438
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardContentSmsDto.java
@@ -0,0 +1,32 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2024/10/21
+ */
+@Getter
+@Setter
+public class RewardContentSmsDto extends FwDto {
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Long ruleRecordNo;
+
+ private String ruleId;
+
+ private ReferenceData smsBrand;
+
+ private ReferenceData messageId;
+
+ private String message;
+
+ private boolean refusedPromotion;
+
+ private String messageCode;
+
+ private String phone;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardNotificationButtonDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardNotificationButtonDto.java
new file mode 100644
index 0000000..331592d
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RewardNotificationButtonDto.java
@@ -0,0 +1,47 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.*;
+
+
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class RewardNotificationButtonDto extends FwDto {
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING)
+ private Long ruleRecordNo;
+
+ private String ruleId;
+
+ private String messageId;
+
+ private String notificationContentId;
+
+ private String buttonId;
+
+ private String buttonName;
+
+ private ReferenceData buttonNavigationType;
+
+ private String buttonLink;
+
+ private ReferenceData buttonTargetScreen;
+
+ private ReferenceData buttonPoolId;
+
+ private ReferenceData buttonOfferGroup;
+
+ private ReferenceData buttonCategoryId;
+
+ private ReferenceData buttonCampaignId;
+
+ private ReferenceData buttonItemCode;
+
+ private ReferenceData buttonReferenceNo;
+
+ private ReferenceData buttonNotificationType;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RuleCriteriaDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RuleCriteriaDto.java
new file mode 100644
index 0000000..672ecf0
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/RuleCriteriaDto.java
@@ -0,0 +1,60 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import lombok.Data;
+import lombok.ToString;
+import org.apache.commons.lang3.StringUtils;
+
+@ToString
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RuleCriteriaDto {
+
+ private String field;
+
+ private String fieldType;
+
+ private String operator;
+
+ private Object[] filterValue;
+
+ private String filterType;
+
+ private String combinator;
+
+ private List rules = new ArrayList<>();
+
+ public boolean isSimple() {
+ return !isGroup();
+ }
+
+ public boolean isGroup() {
+ return !(rules == null || rules.isEmpty());
+ }
+
+ public boolean isEmpty() {
+ return StringUtils.isEmpty(field) && StringUtils.isEmpty(fieldType) && (rules == null || rules.isEmpty());
+ }
+
+ public void validateSimple(RuleCriteriaDto rule, List errors) {
+ if (StringUtils.isEmpty(rule.getField())) {
+ errors.add("Field is required. " + rule.devLog());
+ }
+ if (StringUtils.isEmpty(rule.getOperator())) {
+ errors.add("Operator is required. " + rule.devLog());
+ }
+ if (StringUtils.isEmpty(rule.getFieldType())) {
+ errors.add("Field type is required. " + rule.devLog());
+ }
+ }
+
+ private String devLog() {
+ return String.format(
+ "field: [%s], fieldType: [%s], operator: [%s], filterValue: [%s], filterType: [%s]",
+ field, fieldType, operator, Arrays.toString(filterValue), filterType);
+ }
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/StatementOutputPoolDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/StatementOutputPoolDto.java
new file mode 100644
index 0000000..094205a
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/StatementOutputPoolDto.java
@@ -0,0 +1,29 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import java.time.LocalDateTime;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/24
+ */
+@Getter
+@Setter
+public class StatementOutputPoolDto extends FwDto {
+
+ private String poolId;
+
+ private String poolSeqNo;
+
+ private LocalDateTime poolStartDate;
+
+ private LocalDateTime poolEndDate;
+
+ private String footnoteId;
+
+ private String entityLevel;
+
+ private String poolGroup;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/TransactionCategoryDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/TransactionCategoryDto.java
new file mode 100644
index 0000000..f27053a
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/TransactionCategoryDto.java
@@ -0,0 +1,25 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/31
+ */
+@Getter
+@Setter
+public class TransactionCategoryDto extends FwDto {
+
+ @NotBlank
+ private String code;
+
+ @NotBlank
+ private String name;
+
+ private String description;
+
+ private String criteria;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/TransactionCodeDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/TransactionCodeDto.java
new file mode 100644
index 0000000..a33d844
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/TransactionCodeDto.java
@@ -0,0 +1,28 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author AnhDT
+ * Created on 2023/10/19
+ */
+@Getter
+@Setter
+public class TransactionCodeDto extends FwDto {
+
+ @NotBlank
+ @Size(min = 1, max = 10)
+ private String code;
+
+ @NotBlank
+ @Size(min = 1, max = 100)
+ private String description;
+
+ private Boolean reversalInd;
+
+ private String externalTransactionCode;
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/VelocityControlDto.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/VelocityControlDto.java
new file mode 100644
index 0000000..ffc895f
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/reward/model/VelocityControlDto.java
@@ -0,0 +1,47 @@
+
+package dev.sonpx.loyalty.mcp.reward.model;
+
+
+
+
+
+import dev.sonpx.loyalty.mcp.enums.EntityLevel;
+import dev.sonpx.loyalty.mcp.reward.enums.MerchantEntityLevel;
+import dev.sonpx.loyalty.mcp.reward.enums.VelocityPeriod;
+import dev.sonpx.loyalty.mcp.reward.enums.VelocityTransactionType;
+import dev.sonpx.loyalty.mcp.reward.enums.VelocityUnit;
+import jakarta.validation.constraints.Digits;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * PhuDao created on 16/10/2023
+ */
+@Getter
+@Setter
+public class VelocityControlDto extends FwDto {
+
+ private Long poolRecordNo;
+
+ private String poolId;
+
+ @NotNull
+ @Digits(integer = 10, fraction = 2)
+ private BigDecimal maximum;
+
+ private VelocityTransactionType txnType;
+
+ private VelocityUnit units;
+
+ private EntityLevel perEntity1;
+
+ private MerchantEntityLevel perEntity2;
+
+ private VelocityPeriod perPeriod;
+
+ private String alertGroup; // lookup data - pending
+
+ private String alertTemplate; // lookup data - pending
+}
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/LoyaltyAgentTools.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/LoyaltyAgentTools.java
index 14bd9c9..0522068 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/LoyaltyAgentTools.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/LoyaltyAgentTools.java
@@ -3,16 +3,10 @@ package dev.sonpx.loyalty.mcp.tool;
import dev.sonpx.loyalty.mcp.client.api.CampaignApiClient;
import dev.sonpx.loyalty.mcp.client.api.MemberTierApiClient;
import dev.sonpx.loyalty.mcp.client.api.PointPoolApiClient;
+import dev.sonpx.loyalty.mcp.client.model.*;
import dev.sonpx.loyalty.mcp.client.model.attribute.StaticAttributeDto;
-
-import dev.sonpx.loyalty.mcp.client.model.Campaign;
-import dev.sonpx.loyalty.mcp.client.model.CreateCampaignRequest;
-import dev.sonpx.loyalty.mcp.client.model.MemberTier;
-import dev.sonpx.loyalty.mcp.client.model.OperationResult;
-import dev.sonpx.loyalty.mcp.client.model.PointPool;
-import org.springframework.ai.tool.annotation.Tool;
-
import java.util.List;
+import org.springframework.ai.tool.annotation.Tool;
import org.springframework.core.ParameterizedTypeReference;
public class LoyaltyAgentTools {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/pool/PointPoolTools.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/pool/PointPoolTools.java
index 8ab5e93..ada67ab 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/pool/PointPoolTools.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/pool/PointPoolTools.java
@@ -4,14 +4,13 @@ import dev.sonpx.loyalty.mcp.draft.DependencyValidator;
import dev.sonpx.loyalty.mcp.draft.DraftSessionManager;
import dev.sonpx.loyalty.mcp.tool.model.pool.CreatePoolDefinitionRequest;
import dev.sonpx.loyalty.mcp.tool.model.pool.CreateSopRequest;
+import java.util.Map;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
-import java.util.Map;
-
@Component
public class PointPoolTools {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignRuleMapper.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignRuleMapper.java
index 3fcc441..14dad6b 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignRuleMapper.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignRuleMapper.java
@@ -1,13 +1,12 @@
package dev.sonpx.loyalty.mcp.tool.reward;
+import dev.sonpx.loyalty.mcp.client.model.reward.CampaignFormulaOneDto;
import dev.sonpx.loyalty.mcp.client.model.reward.CampaignRuleDto;
import dev.sonpx.loyalty.mcp.client.model.reward.ReferenceData;
-import dev.sonpx.loyalty.mcp.client.model.reward.CampaignFormulaOneDto;
import dev.sonpx.loyalty.mcp.tool.model.reward.CreateCampaignRuleToolRequest;
import dev.sonpx.loyalty.mcp.tool.model.reward.UpdateCampaignRuleToolRequest;
-import org.springframework.stereotype.Component;
-
import java.util.ArrayList;
+import org.springframework.stereotype.Component;
@Component
public class CampaignRuleMapper {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignRuleTools.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignRuleTools.java
index 2b07104..55e56a4 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignRuleTools.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignRuleTools.java
@@ -1,26 +1,23 @@
package dev.sonpx.loyalty.mcp.tool.reward;
+
import dev.sonpx.loyalty.mcp.client.model.reward.CampaignRuleDto;
import dev.sonpx.loyalty.mcp.client.model.reward.OperationResultCampaignRuleDto;
import dev.sonpx.loyalty.mcp.draft.DependencyValidator;
import dev.sonpx.loyalty.mcp.draft.DraftSessionManager;
+import dev.sonpx.loyalty.mcp.model.McpResponseWrapper;
+import dev.sonpx.loyalty.mcp.model.Presentation;
import dev.sonpx.loyalty.mcp.tool.model.reward.AddRuleToCampaignRequest;
import dev.sonpx.loyalty.mcp.tool.model.reward.CreateCampaignRuleToolRequest;
import dev.sonpx.loyalty.mcp.tool.model.reward.UpdateCampaignRuleToolRequest;
-import dev.sonpx.loyalty.mcp.tool.model.reward.ListCampaignRuleToolRequest;
-import dev.sonpx.loyalty.mcp.model.McpResponseWrapper;
-import dev.sonpx.loyalty.mcp.model.Presentation;
import dev.sonpx.loyalty.mcp.util.MarkdownGenerator;
-
-import org.springframework.ai.tool.annotation.Tool;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.stereotype.Component;
-
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.ai.tool.annotation.Tool;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
-import org.springframework.web.util.UriComponentsBuilder;
@Component
public class CampaignRuleTools {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignTools.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignTools.java
index d9e5453..4cb6191 100644
--- a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignTools.java
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignTools.java
@@ -4,22 +4,20 @@ import dev.sonpx.loyalty.mcp.client.model.reward.CampaignDto;
import dev.sonpx.loyalty.mcp.draft.DependencyValidator;
import dev.sonpx.loyalty.mcp.draft.DraftSessionManager;
import dev.sonpx.loyalty.mcp.draft.model.DraftSession;
-import dev.sonpx.loyalty.mcp.tool.model.reward.SubmitCampaignDraftRequest;
-import dev.sonpx.loyalty.mcp.tool.model.reward.UpdateCampaignDraftRequest;
import dev.sonpx.loyalty.mcp.model.McpResponseWrapper;
import dev.sonpx.loyalty.mcp.model.Presentation;
+import dev.sonpx.loyalty.mcp.tool.model.reward.SubmitCampaignDraftRequest;
+import dev.sonpx.loyalty.mcp.tool.model.reward.UpdateCampaignDraftRequest;
import dev.sonpx.loyalty.mcp.util.MarkdownGenerator;
+import java.util.List;
+import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import java.util.List;
-import java.util.Map;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Component
public class CampaignTools {
diff --git a/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/web/rest/RewardResource.java b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/web/rest/RewardResource.java
new file mode 100644
index 0000000..fda2f37
--- /dev/null
+++ b/loyalty-mcp-server/src/main/java/dev/sonpx/loyalty/mcp/web/rest/RewardResource.java
@@ -0,0 +1,28 @@
+package dev.sonpx.loyalty.mcp.web.rest;
+
+import dev.sonpx.loyalty.mcp.reward.client.RewardClient;
+import dev.sonpx.loyalty.mcp.reward.criteria.CampaignCriteria;
+import dev.sonpx.loyalty.mcp.reward.model.CampaignDto;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Pageable;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Created by SonPhung on Sunday, 19-Jul-2026
+ **/
+@RestController
+@RequestMapping("/api/reward")
+@RequiredArgsConstructor
+public class RewardResource {
+
+ private final RewardClient rewardClient;
+
+ @GetMapping
+ public ResponseEntity> getAll(CampaignCriteria criteria) {
+ return rewardClient.getAll(criteria, Pageable.ofSize(10));
+ }
+}
diff --git a/loyalty-mcp-server/src/test/java/dev/sonpx/loyalty/mcp/RewardClientTest.java b/loyalty-mcp-server/src/test/java/dev/sonpx/loyalty/mcp/RewardClientTest.java
new file mode 100644
index 0000000..aeacdd1
--- /dev/null
+++ b/loyalty-mcp-server/src/test/java/dev/sonpx/loyalty/mcp/RewardClientTest.java
@@ -0,0 +1,19 @@
+package dev.sonpx.loyalty.mcp;
+
+import dev.sonpx.loyalty.mcp.reward.client.RewardClient;
+import dev.sonpx.loyalty.mcp.reward.criteria.CampaignCriteria;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.domain.Pageable;
+
+@SpringBootTest
+public class RewardClientTest {
+ @Autowired
+ RewardClient rewardClient;
+
+ @Test
+ void test() {
+ rewardClient.getAll(new CampaignCriteria(), Pageable.unpaged());
+ }
+}