diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a084efd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,27 @@
+target
+*.releaseBackup
+release.properties
+
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+*.log
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+.
diff --git a/ms-anti-fraud/pom.xml b/ms-anti-fraud/pom.xml
new file mode 100644
index 0000000..a2b10e3
--- /dev/null
+++ b/ms-anti-fraud/pom.xml
@@ -0,0 +1,55 @@
+
+
+ 4.0.0
+
+ pe.interbank
+ java-code-challenge
+ 1.0-SNAPSHOT
+
+
+ ms-anti-fraud
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+ 3.4.3
+
+
+ org.projectlombok
+ lombok
+ 1.18.36
+ provided
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.18.3
+
+
+ org.springframework.kafka
+ spring-kafka
+ 3.3.3
+
+
+ org.slf4j
+ slf4j-api
+ 2.0.16
+
+
+ pe.interbank
+ utils
+ 1.0-SNAPSHOT
+ compile
+
+
+
+
+ 17
+ 17
+ UTF-8
+
+
+
\ No newline at end of file
diff --git a/ms-anti-fraud/src/main/java/pe/interbank/AntifraudApplication.java b/ms-anti-fraud/src/main/java/pe/interbank/AntifraudApplication.java
new file mode 100644
index 0000000..8100f99
--- /dev/null
+++ b/ms-anti-fraud/src/main/java/pe/interbank/AntifraudApplication.java
@@ -0,0 +1,11 @@
+package pe.interbank;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class AntifraudApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(AntifraudApplication.class, args);
+ }
+}
\ No newline at end of file
diff --git a/ms-anti-fraud/src/main/java/pe/interbank/config/KafkaConfig.java b/ms-anti-fraud/src/main/java/pe/interbank/config/KafkaConfig.java
new file mode 100644
index 0000000..0d88e58
--- /dev/null
+++ b/ms-anti-fraud/src/main/java/pe/interbank/config/KafkaConfig.java
@@ -0,0 +1,35 @@
+package pe.interbank.config;
+
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.core.DefaultKafkaProducerFactory;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.core.ProducerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+public class KafkaConfig {
+
+ @Value("${spring.kafka.bootstrap-servers}")
+ private String bootstrapServers;
+
+ @Bean
+ public ProducerFactory producerFactory() {
+ Map configProps = new HashMap<>();
+ configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
+ configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ return new DefaultKafkaProducerFactory<>(configProps);
+ }
+
+ @Bean
+ public KafkaTemplate kafkaTemplate() {
+ return new KafkaTemplate<>(producerFactory());
+ }
+
+}
diff --git a/ms-anti-fraud/src/main/java/pe/interbank/kafka/ValidateTransactionConsumer.java b/ms-anti-fraud/src/main/java/pe/interbank/kafka/ValidateTransactionConsumer.java
new file mode 100644
index 0000000..2f5cf00
--- /dev/null
+++ b/ms-anti-fraud/src/main/java/pe/interbank/kafka/ValidateTransactionConsumer.java
@@ -0,0 +1,33 @@
+package pe.interbank.kafka;
+
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.annotation.KafkaListener;
+import pe.interbank.model.Transaction;
+import pe.interbank.service.AntiFraudService;
+import pe.interbank.util.JsonUtils;
+
+import static pe.interbank.util.Contants.GROUP_ID_INTERBANK;
+import static pe.interbank.util.Contants.TOPIC_TRANSACTION_CREATED;
+
+@Configuration
+public class ValidateTransactionConsumer {
+
+ private static final Logger logger = org.slf4j.LoggerFactory.getLogger(ValidateTransactionConsumer.class);
+
+ @Autowired
+ private AntiFraudService antiFraudService;
+
+ private final JsonUtils jsonUtils;
+
+ public ValidateTransactionConsumer(JsonUtils jsonUtils) {
+ this.jsonUtils = jsonUtils;
+ }
+
+ @KafkaListener(topics = TOPIC_TRANSACTION_CREATED, groupId = GROUP_ID_INTERBANK)
+ public void consumeTransaction(String message) {
+ logger.info("Consumed message: {}", message);
+ antiFraudService.validateTransaction(jsonUtils.fromJson(message, Transaction.class)).subscribe();
+ }
+}
diff --git a/ms-anti-fraud/src/main/java/pe/interbank/model/Transaction.java b/ms-anti-fraud/src/main/java/pe/interbank/model/Transaction.java
new file mode 100644
index 0000000..bfa130d
--- /dev/null
+++ b/ms-anti-fraud/src/main/java/pe/interbank/model/Transaction.java
@@ -0,0 +1,16 @@
+package pe.interbank.model;
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class Transaction {
+
+ private String accountExternalId;
+ private int tranferTypeId;
+ private Double value;
+ private String status;
+ private Date createdAt;
+ private Date updatedAt;
+}
diff --git a/ms-anti-fraud/src/main/java/pe/interbank/service/AntiFraudService.java b/ms-anti-fraud/src/main/java/pe/interbank/service/AntiFraudService.java
new file mode 100644
index 0000000..e2ba5b5
--- /dev/null
+++ b/ms-anti-fraud/src/main/java/pe/interbank/service/AntiFraudService.java
@@ -0,0 +1,8 @@
+package pe.interbank.service;
+
+import pe.interbank.model.Transaction;
+import reactor.core.publisher.Mono;
+
+public interface AntiFraudService {
+ Mono validateTransaction(Transaction transaction);
+}
diff --git a/ms-anti-fraud/src/main/java/pe/interbank/service/impl/AntiFraudServiceImpl.java b/ms-anti-fraud/src/main/java/pe/interbank/service/impl/AntiFraudServiceImpl.java
new file mode 100644
index 0000000..dec4aa0
--- /dev/null
+++ b/ms-anti-fraud/src/main/java/pe/interbank/service/impl/AntiFraudServiceImpl.java
@@ -0,0 +1,48 @@
+package pe.interbank.service.impl;
+
+import org.slf4j.Logger;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.stereotype.Service;
+import pe.interbank.model.Transaction;
+import pe.interbank.service.AntiFraudService;
+import pe.interbank.util.JsonUtils;
+import pe.interbank.util.StatusTransaction;
+import reactor.core.publisher.Mono;
+
+import static pe.interbank.util.Contants.MAX_AMOUNT;
+import static pe.interbank.util.Contants.TOPIC_TRANSACTION_VALIDATED;
+
+@Service
+public class AntiFraudServiceImpl implements AntiFraudService {
+
+ private static final Logger logger = org.slf4j.LoggerFactory.getLogger(AntiFraudServiceImpl.class);
+
+ private final KafkaTemplate kafkaTemplate;
+ private final JsonUtils jsonUtils;
+
+ public AntiFraudServiceImpl(KafkaTemplate kafkaTemplate, JsonUtils jsonUtils) {
+ this.kafkaTemplate = kafkaTemplate;
+ this.jsonUtils = jsonUtils;
+ }
+
+ @Override
+ public Mono validateTransaction(Transaction transaction) {
+ logger.info("Validating transaction: {}", transaction);
+
+ updateTransactionStatus(transaction);
+
+ String transactionValidated = jsonUtils.toJson(transaction);
+
+ return Mono.fromFuture(kafkaTemplate.send(TOPIC_TRANSACTION_VALIDATED, transactionValidated))
+ .doOnSuccess(s -> logger.info("Transaction VALIDATED sent to kafka: {}", transactionValidated))
+ .then();
+ }
+
+ private void updateTransactionStatus(Transaction transaction) {
+ if (transaction.getValue() > MAX_AMOUNT) {
+ transaction.setStatus(StatusTransaction.RECHAZADO.getDescription());
+ } else {
+ transaction.setStatus(StatusTransaction.APROBADO.getDescription());
+ }
+ }
+}
diff --git a/ms-anti-fraud/src/main/java/pe/interbank/util/JsonUtils.java b/ms-anti-fraud/src/main/java/pe/interbank/util/JsonUtils.java
new file mode 100644
index 0000000..45f8a35
--- /dev/null
+++ b/ms-anti-fraud/src/main/java/pe/interbank/util/JsonUtils.java
@@ -0,0 +1,30 @@
+package pe.interbank.util;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.stereotype.Component;
+
+@Component
+public class JsonUtils {
+ private final ObjectMapper objectMapper;
+
+ public JsonUtils(ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ }
+
+ public String toJson(Object object) {
+ try {
+ return objectMapper.writeValueAsString(object);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("Error converting object to JSON", e);
+ }
+ }
+
+ public T fromJson(String json, Class clazz) {
+ try {
+ return objectMapper.readValue(json, clazz);
+ } catch (Exception e) {
+ throw new RuntimeException("Error parsing JSON", e);
+ }
+ }
+}
diff --git a/ms-anti-fraud/src/main/resources/application.yml b/ms-anti-fraud/src/main/resources/application.yml
new file mode 100644
index 0000000..a077fae
--- /dev/null
+++ b/ms-anti-fraud/src/main/resources/application.yml
@@ -0,0 +1,8 @@
+server:
+ port: 7070
+# Kafka
+spring:
+ kafka:
+ bootstrap-servers: localhost:9092
+ producer:
+ retries: 1
\ No newline at end of file
diff --git a/ms-transaction/pom.xml b/ms-transaction/pom.xml
new file mode 100644
index 0000000..1233182
--- /dev/null
+++ b/ms-transaction/pom.xml
@@ -0,0 +1,71 @@
+
+
+ 4.0.0
+
+ pe.interbank
+ java-code-challenge
+ 1.0-SNAPSHOT
+
+
+ ms-transaction
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.postgresql
+ postgresql
+
+
+ org.springframework.boot
+ spring-boot-starter-reactor-netty
+
+
+ io.projectreactor.netty
+ reactor-netty-http
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ org.springframework.kafka
+ spring-kafka
+
+
+ org.slf4j
+ slf4j-api
+
+
+ pe.interbank
+ utils
+ 1.0-SNAPSHOT
+ compile
+
+
+
+
+
+
+
+
+
+ 17
+ 17
+ UTF-8
+
+
+
\ No newline at end of file
diff --git a/ms-transaction/src/main/java/pe/interbank/TransactionApplication.java b/ms-transaction/src/main/java/pe/interbank/TransactionApplication.java
new file mode 100644
index 0000000..84b8d70
--- /dev/null
+++ b/ms-transaction/src/main/java/pe/interbank/TransactionApplication.java
@@ -0,0 +1,11 @@
+package pe.interbank;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class TransactionApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(TransactionApplication.class, args);
+ }
+}
\ No newline at end of file
diff --git a/ms-transaction/src/main/java/pe/interbank/config/KafkaConfig.java b/ms-transaction/src/main/java/pe/interbank/config/KafkaConfig.java
new file mode 100644
index 0000000..0d88e58
--- /dev/null
+++ b/ms-transaction/src/main/java/pe/interbank/config/KafkaConfig.java
@@ -0,0 +1,35 @@
+package pe.interbank.config;
+
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.core.DefaultKafkaProducerFactory;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.core.ProducerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+public class KafkaConfig {
+
+ @Value("${spring.kafka.bootstrap-servers}")
+ private String bootstrapServers;
+
+ @Bean
+ public ProducerFactory producerFactory() {
+ Map configProps = new HashMap<>();
+ configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
+ configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ return new DefaultKafkaProducerFactory<>(configProps);
+ }
+
+ @Bean
+ public KafkaTemplate kafkaTemplate() {
+ return new KafkaTemplate<>(producerFactory());
+ }
+
+}
diff --git a/ms-transaction/src/main/java/pe/interbank/controller/TransactionController.java b/ms-transaction/src/main/java/pe/interbank/controller/TransactionController.java
new file mode 100644
index 0000000..d15b7cc
--- /dev/null
+++ b/ms-transaction/src/main/java/pe/interbank/controller/TransactionController.java
@@ -0,0 +1,31 @@
+package pe.interbank.controller;
+
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import pe.interbank.model.DTO.TransactionRequest;
+import pe.interbank.model.Transaction;
+import pe.interbank.service.TransactionService;
+import pe.interbank.service.impl.TransactionServiceImpl;
+import reactor.core.publisher.Mono;
+
+@RestController
+@RequestMapping("/transaction")
+public class TransactionController {
+
+ private static final Logger logger = org.slf4j.LoggerFactory.getLogger(TransactionController.class);
+
+ @Autowired
+ TransactionService transactionService;
+
+ @GetMapping("/{accountExternalId}")
+ public Mono getTransaction(@PathVariable("accountExternalId") String accountExternalId) {
+ return transactionService.getTransaction(accountExternalId);
+ }
+
+ @PostMapping
+ public Mono sendTransaction(@RequestBody TransactionRequest transactionRq) {
+ return transactionService.sendTransaction(transactionRq);
+ }
+
+}
diff --git a/ms-transaction/src/main/java/pe/interbank/kafka/TransactionConsumer.java b/ms-transaction/src/main/java/pe/interbank/kafka/TransactionConsumer.java
new file mode 100644
index 0000000..be33adf
--- /dev/null
+++ b/ms-transaction/src/main/java/pe/interbank/kafka/TransactionConsumer.java
@@ -0,0 +1,32 @@
+package pe.interbank.kafka;
+
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.annotation.KafkaListener;
+import pe.interbank.model.Transaction;
+import pe.interbank.service.TransactionService;
+import pe.interbank.util.JsonUtils;
+
+import static pe.interbank.util.Contants.*;
+
+@Configuration
+public class TransactionConsumer {
+
+ private static final Logger logger = org.slf4j.LoggerFactory.getLogger(TransactionConsumer.class);
+
+ @Autowired
+ private TransactionService transactionService;
+
+ private final JsonUtils jsonUtils;
+
+ public TransactionConsumer(JsonUtils jsonUtils) {
+ this.jsonUtils = jsonUtils;
+ }
+
+ @KafkaListener(topics = TOPIC_TRANSACTION_VALIDATED, groupId = GROUP_ID_INTERBANK)
+ public void consumeTransaction(String message) {
+ logger.info("Topic {}: Consumed message: {}", TOPIC_TRANSACTION_VALIDATED, message);
+ transactionService.updateTransactionStatus(jsonUtils.fromJson(message, Transaction.class)).subscribe();
+ }
+}
diff --git a/ms-transaction/src/main/java/pe/interbank/model/DTO/TransactionRequest.java b/ms-transaction/src/main/java/pe/interbank/model/DTO/TransactionRequest.java
new file mode 100644
index 0000000..2ef7a91
--- /dev/null
+++ b/ms-transaction/src/main/java/pe/interbank/model/DTO/TransactionRequest.java
@@ -0,0 +1,15 @@
+package pe.interbank.model.DTO;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class TransactionRequest {
+ private int tranferTypeId;
+ private Double value;
+}
diff --git a/ms-transaction/src/main/java/pe/interbank/model/Transaction.java b/ms-transaction/src/main/java/pe/interbank/model/Transaction.java
new file mode 100644
index 0000000..a331a50
--- /dev/null
+++ b/ms-transaction/src/main/java/pe/interbank/model/Transaction.java
@@ -0,0 +1,35 @@
+package pe.interbank.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+
+@Entity
+@Table(name = "transaction")
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class Transaction {
+
+ @Id
+ private String accountExternalId;
+
+ private int tranferTypeId;
+
+ private Double value;
+
+ private String status;
+
+ private Date createdAt;
+
+ private Date updatedAt;
+}
diff --git a/ms-transaction/src/main/java/pe/interbank/repository/TransactionRepository.java b/ms-transaction/src/main/java/pe/interbank/repository/TransactionRepository.java
new file mode 100644
index 0000000..6e590b0
--- /dev/null
+++ b/ms-transaction/src/main/java/pe/interbank/repository/TransactionRepository.java
@@ -0,0 +1,9 @@
+package pe.interbank.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+import pe.interbank.model.Transaction;
+
+@Repository
+public interface TransactionRepository extends JpaRepository {
+}
diff --git a/ms-transaction/src/main/java/pe/interbank/service/TransactionService.java b/ms-transaction/src/main/java/pe/interbank/service/TransactionService.java
new file mode 100644
index 0000000..59bf9c4
--- /dev/null
+++ b/ms-transaction/src/main/java/pe/interbank/service/TransactionService.java
@@ -0,0 +1,14 @@
+package pe.interbank.service;
+
+import pe.interbank.model.DTO.TransactionRequest;
+import pe.interbank.model.Transaction;
+import reactor.core.publisher.Mono;
+
+public interface TransactionService {
+
+ Mono getTransaction(String accountExternalId);
+
+ Mono sendTransaction(TransactionRequest transactionRq);
+
+ Mono updateTransactionStatus(Transaction transaction);
+}
diff --git a/ms-transaction/src/main/java/pe/interbank/service/impl/TransactionServiceImpl.java b/ms-transaction/src/main/java/pe/interbank/service/impl/TransactionServiceImpl.java
new file mode 100644
index 0000000..e4f6b78
--- /dev/null
+++ b/ms-transaction/src/main/java/pe/interbank/service/impl/TransactionServiceImpl.java
@@ -0,0 +1,84 @@
+package pe.interbank.service.impl;
+
+import org.slf4j.Logger;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.stereotype.Service;
+import pe.interbank.model.DTO.TransactionRequest;
+import pe.interbank.model.Transaction;
+import pe.interbank.repository.TransactionRepository;
+import pe.interbank.service.TransactionService;
+import pe.interbank.util.JsonUtils;
+import pe.interbank.util.StatusTransaction;
+import reactor.core.publisher.Mono;
+
+import java.util.Date;
+import java.util.Optional;
+import java.util.UUID;
+
+import static pe.interbank.util.Contants.TOPIC_TRANSACTION_CREATED;
+
+@Service
+public class TransactionServiceImpl implements TransactionService {
+
+ private static final Logger logger = org.slf4j.LoggerFactory.getLogger(TransactionServiceImpl.class);
+
+ private final TransactionRepository transactionRepository;
+
+ private final KafkaTemplate kafkaTemplate;
+ private final JsonUtils jsonUtils;
+
+ public TransactionServiceImpl(TransactionRepository transactionRepository, KafkaTemplate kafkaTemplate, JsonUtils jsonUtils) {
+ this.transactionRepository = transactionRepository;
+ this.kafkaTemplate = kafkaTemplate;
+ this.jsonUtils = jsonUtils;
+ }
+
+ @Override
+ public Mono getTransaction(String accountExternalId) {
+ Optional transaction = transactionRepository.findById(accountExternalId);
+
+ if (!transaction.isPresent()) {
+ logger.error("Transaction not found: {}", accountExternalId);
+ return Mono.empty();
+ }
+
+ return Mono.just(transaction.get());
+ }
+
+ @Override
+ public Mono sendTransaction(TransactionRequest transactionRq) {
+ Transaction transaction = Transaction.builder()
+ .accountExternalId(UUID.randomUUID().toString())
+ .tranferTypeId(transactionRq.getTranferTypeId())
+ .value(transactionRq.getValue())
+ .status(StatusTransaction.PENDIENTE.getDescription())
+ .createdAt(new Date())
+ .build();
+
+ Transaction transactionSaved = transactionRepository.save(transaction);
+ logger.info("Transaction created: {}", transactionSaved);
+
+ String transactionJson = jsonUtils.toJson(transactionSaved);
+ kafkaTemplate.send(TOPIC_TRANSACTION_CREATED, transactionJson);
+ logger.info("Transaction PENDIENTE sent to kafka: {}", transactionJson);
+
+ return Mono.just(transactionSaved);
+ }
+
+ @Override
+ public Mono updateTransactionStatus(Transaction transactionRq) {
+
+ Optional transaction = transactionRepository.findById(transactionRq.getAccountExternalId());
+
+ if (transaction.isPresent()) {
+ Transaction transactionToUpdate = transaction.get();
+ transactionToUpdate.setStatus(transactionRq.getStatus());
+ transactionToUpdate.setUpdatedAt(new Date());
+ transactionRepository.save(transactionToUpdate);
+ logger.info("Transaction updated: {}", transactionToUpdate);
+ }
+
+ return Mono.empty();
+ }
+
+}
diff --git a/ms-transaction/src/main/java/pe/interbank/util/JsonUtils.java b/ms-transaction/src/main/java/pe/interbank/util/JsonUtils.java
new file mode 100644
index 0000000..45f8a35
--- /dev/null
+++ b/ms-transaction/src/main/java/pe/interbank/util/JsonUtils.java
@@ -0,0 +1,30 @@
+package pe.interbank.util;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.stereotype.Component;
+
+@Component
+public class JsonUtils {
+ private final ObjectMapper objectMapper;
+
+ public JsonUtils(ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ }
+
+ public String toJson(Object object) {
+ try {
+ return objectMapper.writeValueAsString(object);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("Error converting object to JSON", e);
+ }
+ }
+
+ public T fromJson(String json, Class clazz) {
+ try {
+ return objectMapper.readValue(json, clazz);
+ } catch (Exception e) {
+ throw new RuntimeException("Error parsing JSON", e);
+ }
+ }
+}
diff --git a/ms-transaction/src/main/resources/application.yml b/ms-transaction/src/main/resources/application.yml
new file mode 100644
index 0000000..33f7957
--- /dev/null
+++ b/ms-transaction/src/main/resources/application.yml
@@ -0,0 +1,19 @@
+server:
+ port: 8080
+spring:
+ datasource:
+ url: jdbc:postgresql://localhost:5432/db_fraud
+ username: postgres
+ password: postgres
+ driver-class-name: org.postgresql.Driver
+ jpa:
+ database: POSTGRESQL
+ generate-ddl: true
+ database-platform: org.hibernate.dialect.PostgreSQLDialect
+
+ # Kafka
+ kafka:
+ bootstrap-servers: localhost:9092
+ producer:
+ retries: 1
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..141ac02
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,74 @@
+
+
+ 4.0.0
+
+ pe.interbank
+ java-code-challenge
+ 1.0-SNAPSHOT
+ pom
+
+ ms-anti-fraud
+ ms-transaction
+ utils
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+ 3.4.3
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+ 3.4.3
+
+
+ org.postgresql
+ postgresql
+ 42.7.5
+
+
+ org.springframework.boot
+ spring-boot-starter-reactor-netty
+ 3.4.3
+
+
+ io.projectreactor.netty
+ reactor-netty-http
+ 1.2.1
+
+
+ org.projectlombok
+ lombok
+ 1.18.36
+ provided
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.18.3
+
+
+ org.springframework.kafka
+ spring-kafka
+ 3.3.3
+
+
+ org.slf4j
+ slf4j-api
+ 2.0.16
+
+
+
+
+
+ 17
+ 17
+ UTF-8
+
+
+
\ No newline at end of file
diff --git a/utils/pom.xml b/utils/pom.xml
new file mode 100644
index 0000000..2e364ba
--- /dev/null
+++ b/utils/pom.xml
@@ -0,0 +1,20 @@
+
+
+ 4.0.0
+
+ pe.interbank
+ java-code-challenge
+ 1.0-SNAPSHOT
+
+
+ utils
+
+
+ 17
+ 17
+ UTF-8
+
+
+
\ No newline at end of file
diff --git a/utils/src/main/java/pe/interbank/util/Contants.java b/utils/src/main/java/pe/interbank/util/Contants.java
new file mode 100644
index 0000000..43f3e42
--- /dev/null
+++ b/utils/src/main/java/pe/interbank/util/Contants.java
@@ -0,0 +1,12 @@
+package pe.interbank.util;
+
+public class Contants {
+
+ // KAFKA
+ public static final String GROUP_ID_INTERBANK = "pe.interbank";
+ public static final String TOPIC_TRANSACTION_CREATED = "topic-transaction-created";
+ public static final String TOPIC_TRANSACTION_VALIDATED = "topic-transaction-validated";
+
+ // AMOUNT
+ public static final Double MAX_AMOUNT = 1000.0;
+}
diff --git a/utils/src/main/java/pe/interbank/util/StatusTransaction.java b/utils/src/main/java/pe/interbank/util/StatusTransaction.java
new file mode 100644
index 0000000..0e06a4c
--- /dev/null
+++ b/utils/src/main/java/pe/interbank/util/StatusTransaction.java
@@ -0,0 +1,17 @@
+package pe.interbank.util;
+
+public enum StatusTransaction {
+ PENDIENTE("PENDIENTE"),
+ APROBADO("APROBADO"),
+ RECHAZADO("RECHAZADO");
+
+ private String description;
+
+ StatusTransaction(String description) {
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+}
diff --git a/utils/src/main/java/pe/interbank/util/TypeTransaction.java b/utils/src/main/java/pe/interbank/util/TypeTransaction.java
new file mode 100644
index 0000000..cfbd895
--- /dev/null
+++ b/utils/src/main/java/pe/interbank/util/TypeTransaction.java
@@ -0,0 +1,22 @@
+package pe.interbank.util;
+
+public enum TypeTransaction {
+ CREDIT(1, "CREDITO"),
+ DEBIT(2, "DEBITO");
+
+ private int type;
+ private String description;
+
+ TypeTransaction(int type, String description) {
+ this.type = type;
+ this.description = description;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+}