From d1430138578d0243bc9edef6e6d362d6cceef30a Mon Sep 17 00:00:00 2001 From: GiancaS4 <141766223+GiancaS4@users.noreply.github.com> Date: Tue, 6 Jan 2026 02:29:43 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20Soluci=C3=B3n=20Yape=20Challenge=20Java?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- antifraud/.classpath | 32 ++++++ antifraud/.project | 23 +++++ .../org.eclipse.core.resources.prefs | 4 + .../.settings/org.eclipse.jdt.core.prefs | 9 ++ antifraud/Dockerfile | 11 +++ antifraud/pom.xml | 53 ++++++++++ .../yape/antifraud/AntifraudApplication.java | 11 +++ .../antifraud/kafka/AntiFraudListener.java | 28 ++++++ .../yape/antifraud/kafka/StatusPublisher.java | 24 +++++ .../kafka/TransactionCreatedEvent.java | 12 +++ .../kafka/TransactionStatusEvent.java | 6 ++ antifraud/src/main/resources/application.yml | 22 +++++ antifraud/target/classes/application.yml | 22 +++++ .../yape/antifraud/AntifraudApplication.class | Bin 0 -> 752 bytes .../antifraud/kafka/AntiFraudListener.class | Bin 0 -> 1806 bytes .../antifraud/kafka/StatusPublisher.class | Bin 0 -> 1658 bytes .../kafka/TransactionCreatedEvent.class | Bin 0 -> 2351 bytes .../kafka/TransactionStatusEvent.class | Bin 0 -> 1585 bytes transaction/.classpath | 32 ++++++ transaction/.project | 23 +++++ .../org.eclipse.core.resources.prefs | 4 + .../.settings/org.eclipse.jdt.core.prefs | 9 ++ transaction/Dockerfile | 11 +++ transaction/pom.xml | 75 ++++++++++++++ .../transactions/TransactionsApplication.java | 11 +++ .../transactions/api/ApiExceptionHandler.java | 34 +++++++ .../api/TransactionController.java | 31 ++++++ .../api/dto/CreateTransactionRequest.java | 14 +++ .../api/dto/CreateTransactionResponse.java | 3 + .../api/dto/TransactionResponse.java | 14 +++ .../domain/TransactionEntity.java | 92 ++++++++++++++++++ .../domain/TransactionRepository.java | 9 ++ .../kafka/TransactionCreatedEvent.java | 12 +++ .../kafka/TransactionEventsPublisher.java | 24 +++++ .../kafka/TransactionStatusEvent.java | 6 ++ .../kafka/TransactionStatusListener.java | 42 ++++++++ .../service/InvalidUuidException.java | 7 ++ .../service/TransactionNotFoundException.java | 7 ++ .../service/TransactionService.java | 76 +++++++++++++++ .../src/main/resources/application.yml | 34 +++++++ transaction/target/classes/application.yml | 34 +++++++ .../TransactionsApplication.class | Bin 0 -> 767 bytes .../api/ApiExceptionHandler.class | Bin 0 -> 4282 bytes .../api/TransactionController.class | Bin 0 -> 2457 bytes .../api/dto/CreateTransactionRequest.class | Bin 0 -> 2721 bytes .../api/dto/CreateTransactionResponse.class | Bin 0 -> 1470 bytes .../dto/TransactionResponse$NamedDto.class | Bin 0 -> 1555 bytes .../api/dto/TransactionResponse.class | Bin 0 -> 2462 bytes .../domain/TransactionEntity.class | Bin 0 -> 2669 bytes .../domain/TransactionRepository.class | Bin 0 -> 607 bytes .../kafka/TransactionCreatedEvent.class | Bin 0 -> 2366 bytes .../kafka/TransactionEventsPublisher.class | Bin 0 -> 1726 bytes .../kafka/TransactionStatusEvent.class | Bin 0 -> 1600 bytes .../kafka/TransactionStatusListener.class | Bin 0 -> 3101 bytes .../service/InvalidUuidException.class | Bin 0 -> 625 bytes .../TransactionNotFoundException.class | Bin 0 -> 665 bytes .../service/TransactionService.class | Bin 0 -> 4745 bytes 57 files changed, 861 insertions(+) create mode 100644 antifraud/.classpath create mode 100644 antifraud/.project create mode 100644 antifraud/.settings/org.eclipse.core.resources.prefs create mode 100644 antifraud/.settings/org.eclipse.jdt.core.prefs create mode 100644 antifraud/Dockerfile create mode 100644 antifraud/pom.xml create mode 100644 antifraud/src/main/java/com/yape/antifraud/AntifraudApplication.java create mode 100644 antifraud/src/main/java/com/yape/antifraud/kafka/AntiFraudListener.java create mode 100644 antifraud/src/main/java/com/yape/antifraud/kafka/StatusPublisher.java create mode 100644 antifraud/src/main/java/com/yape/antifraud/kafka/TransactionCreatedEvent.java create mode 100644 antifraud/src/main/java/com/yape/antifraud/kafka/TransactionStatusEvent.java create mode 100644 antifraud/src/main/resources/application.yml create mode 100644 antifraud/target/classes/application.yml create mode 100644 antifraud/target/classes/com/yape/antifraud/AntifraudApplication.class create mode 100644 antifraud/target/classes/com/yape/antifraud/kafka/AntiFraudListener.class create mode 100644 antifraud/target/classes/com/yape/antifraud/kafka/StatusPublisher.class create mode 100644 antifraud/target/classes/com/yape/antifraud/kafka/TransactionCreatedEvent.class create mode 100644 antifraud/target/classes/com/yape/antifraud/kafka/TransactionStatusEvent.class create mode 100644 transaction/.classpath create mode 100644 transaction/.project create mode 100644 transaction/.settings/org.eclipse.core.resources.prefs create mode 100644 transaction/.settings/org.eclipse.jdt.core.prefs create mode 100644 transaction/Dockerfile create mode 100644 transaction/pom.xml create mode 100644 transaction/src/main/java/com/yape/transactions/TransactionsApplication.java create mode 100644 transaction/src/main/java/com/yape/transactions/api/ApiExceptionHandler.java create mode 100644 transaction/src/main/java/com/yape/transactions/api/TransactionController.java create mode 100644 transaction/src/main/java/com/yape/transactions/api/dto/CreateTransactionRequest.java create mode 100644 transaction/src/main/java/com/yape/transactions/api/dto/CreateTransactionResponse.java create mode 100644 transaction/src/main/java/com/yape/transactions/api/dto/TransactionResponse.java create mode 100644 transaction/src/main/java/com/yape/transactions/domain/TransactionEntity.java create mode 100644 transaction/src/main/java/com/yape/transactions/domain/TransactionRepository.java create mode 100644 transaction/src/main/java/com/yape/transactions/kafka/TransactionCreatedEvent.java create mode 100644 transaction/src/main/java/com/yape/transactions/kafka/TransactionEventsPublisher.java create mode 100644 transaction/src/main/java/com/yape/transactions/kafka/TransactionStatusEvent.java create mode 100644 transaction/src/main/java/com/yape/transactions/kafka/TransactionStatusListener.java create mode 100644 transaction/src/main/java/com/yape/transactions/service/InvalidUuidException.java create mode 100644 transaction/src/main/java/com/yape/transactions/service/TransactionNotFoundException.java create mode 100644 transaction/src/main/java/com/yape/transactions/service/TransactionService.java create mode 100644 transaction/src/main/resources/application.yml create mode 100644 transaction/target/classes/application.yml create mode 100644 transaction/target/classes/com/yape/transactions/TransactionsApplication.class create mode 100644 transaction/target/classes/com/yape/transactions/api/ApiExceptionHandler.class create mode 100644 transaction/target/classes/com/yape/transactions/api/TransactionController.class create mode 100644 transaction/target/classes/com/yape/transactions/api/dto/CreateTransactionRequest.class create mode 100644 transaction/target/classes/com/yape/transactions/api/dto/CreateTransactionResponse.class create mode 100644 transaction/target/classes/com/yape/transactions/api/dto/TransactionResponse$NamedDto.class create mode 100644 transaction/target/classes/com/yape/transactions/api/dto/TransactionResponse.class create mode 100644 transaction/target/classes/com/yape/transactions/domain/TransactionEntity.class create mode 100644 transaction/target/classes/com/yape/transactions/domain/TransactionRepository.class create mode 100644 transaction/target/classes/com/yape/transactions/kafka/TransactionCreatedEvent.class create mode 100644 transaction/target/classes/com/yape/transactions/kafka/TransactionEventsPublisher.class create mode 100644 transaction/target/classes/com/yape/transactions/kafka/TransactionStatusEvent.class create mode 100644 transaction/target/classes/com/yape/transactions/kafka/TransactionStatusListener.class create mode 100644 transaction/target/classes/com/yape/transactions/service/InvalidUuidException.class create mode 100644 transaction/target/classes/com/yape/transactions/service/TransactionNotFoundException.class create mode 100644 transaction/target/classes/com/yape/transactions/service/TransactionService.class diff --git a/antifraud/.classpath b/antifraud/.classpath new file mode 100644 index 0000000000..c8ae32e9a3 --- /dev/null +++ b/antifraud/.classpath @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/antifraud/.project b/antifraud/.project new file mode 100644 index 0000000000..23f4adfa97 --- /dev/null +++ b/antifraud/.project @@ -0,0 +1,23 @@ + + + antifraud + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/antifraud/.settings/org.eclipse.core.resources.prefs b/antifraud/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..abdea9ac03 --- /dev/null +++ b/antifraud/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding/=UTF-8 diff --git a/antifraud/.settings/org.eclipse.jdt.core.prefs b/antifraud/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..5b8827bcae --- /dev/null +++ b/antifraud/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.methodParameters=generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=16 +org.eclipse.jdt.core.compiler.compliance=16 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=16 diff --git a/antifraud/Dockerfile b/antifraud/Dockerfile new file mode 100644 index 0000000000..31d100bac5 --- /dev/null +++ b/antifraud/Dockerfile @@ -0,0 +1,11 @@ +FROM maven:3.9.9-eclipse-temurin-17 AS build +WORKDIR /app +COPY pom.xml . +COPY src ./src +RUN mvn -q -DskipTests package + +FROM eclipse-temurin:17-jre +WORKDIR /app +COPY --from=build /app/target/antifraud-service-0.0.1-SNAPSHOT.jar app.jar +EXPOSE 8081 +ENTRYPOINT ["java","-jar","/app/app.jar"] diff --git a/antifraud/pom.xml b/antifraud/pom.xml new file mode 100644 index 0000000000..976430fae8 --- /dev/null +++ b/antifraud/pom.xml @@ -0,0 +1,53 @@ + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.7 + + + + com.yape + antifraud-service + 0.0.1-SNAPSHOT + antifraud-service + + + 17 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.kafka + spring-kafka + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/antifraud/src/main/java/com/yape/antifraud/AntifraudApplication.java b/antifraud/src/main/java/com/yape/antifraud/AntifraudApplication.java new file mode 100644 index 0000000000..a0f21e39f8 --- /dev/null +++ b/antifraud/src/main/java/com/yape/antifraud/AntifraudApplication.java @@ -0,0 +1,11 @@ +package com.yape.antifraud; + +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); + } +} diff --git a/antifraud/src/main/java/com/yape/antifraud/kafka/AntiFraudListener.java b/antifraud/src/main/java/com/yape/antifraud/kafka/AntiFraudListener.java new file mode 100644 index 0000000000..dc460035b0 --- /dev/null +++ b/antifraud/src/main/java/com/yape/antifraud/kafka/AntiFraudListener.java @@ -0,0 +1,28 @@ +package com.yape.antifraud.kafka; + +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; + +@Component +public class AntiFraudListener { + + private final StatusPublisher publisher; + + public AntiFraudListener(StatusPublisher publisher) { + this.publisher = publisher; + } + + @KafkaListener(topics = "${app.topics.created}", groupId = "antifraud-service") + public void onCreated(TransactionCreatedEvent event) { + String status = decide(event.value()); + publisher.publish(new TransactionStatusEvent(event.transactionExternalId(), status)); + } + + private String decide(BigDecimal value) { + if (value == null) return "rejected"; + // Regla del reto: value > 1000 => rejected + return value.compareTo(BigDecimal.valueOf(1000)) > 0 ? "rejected" : "approved"; + } +} diff --git a/antifraud/src/main/java/com/yape/antifraud/kafka/StatusPublisher.java b/antifraud/src/main/java/com/yape/antifraud/kafka/StatusPublisher.java new file mode 100644 index 0000000000..889a71e105 --- /dev/null +++ b/antifraud/src/main/java/com/yape/antifraud/kafka/StatusPublisher.java @@ -0,0 +1,24 @@ +package com.yape.antifraud.kafka; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; + +@Component +public class StatusPublisher { + + private final KafkaTemplate kafkaTemplate; + private final String statusTopic; + + public StatusPublisher( + KafkaTemplate kafkaTemplate, + @Value("${app.topics.status}") String statusTopic + ) { + this.kafkaTemplate = kafkaTemplate; + this.statusTopic = statusTopic; + } + + public void publish(TransactionStatusEvent event) { + kafkaTemplate.send(statusTopic, event.transactionExternalId(), event); + } +} diff --git a/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionCreatedEvent.java b/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionCreatedEvent.java new file mode 100644 index 0000000000..ae24dc3b8b --- /dev/null +++ b/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionCreatedEvent.java @@ -0,0 +1,12 @@ +package com.yape.antifraud.kafka; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; + +public record TransactionCreatedEvent( + String transactionExternalId, + String accountExternalIdDebit, + String accountExternalIdCredit, + @JsonProperty("tranferTypeId") Integer tranferTypeId, + BigDecimal value +) {} diff --git a/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionStatusEvent.java b/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionStatusEvent.java new file mode 100644 index 0000000000..a3da17d9a6 --- /dev/null +++ b/antifraud/src/main/java/com/yape/antifraud/kafka/TransactionStatusEvent.java @@ -0,0 +1,6 @@ +package com.yape.antifraud.kafka; + +public record TransactionStatusEvent( + String transactionExternalId, + String status +) {} diff --git a/antifraud/src/main/resources/application.yml b/antifraud/src/main/resources/application.yml new file mode 100644 index 0000000000..e17395abc6 --- /dev/null +++ b/antifraud/src/main/resources/application.yml @@ -0,0 +1,22 @@ +server: + port: 8081 + +spring: + kafka: + bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:localhost:29092} + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer + consumer: + group-id: antifraud-service + auto-offset-reset: earliest + key-deserializer: org.apache.kafka.common.serialization.StringDeserializer + value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer + properties: + spring.json.trusted.packages: "*" + spring.json.value.default.type: com.yape.antifraud.kafka.TransactionCreatedEvent + +app: + topics: + created: transactions.created + status: transactions.status diff --git a/antifraud/target/classes/application.yml b/antifraud/target/classes/application.yml new file mode 100644 index 0000000000..e17395abc6 --- /dev/null +++ b/antifraud/target/classes/application.yml @@ -0,0 +1,22 @@ +server: + port: 8081 + +spring: + kafka: + bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:localhost:29092} + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer + consumer: + group-id: antifraud-service + auto-offset-reset: earliest + key-deserializer: org.apache.kafka.common.serialization.StringDeserializer + value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer + properties: + spring.json.trusted.packages: "*" + spring.json.value.default.type: com.yape.antifraud.kafka.TransactionCreatedEvent + +app: + topics: + created: transactions.created + status: transactions.status diff --git a/antifraud/target/classes/com/yape/antifraud/AntifraudApplication.class b/antifraud/target/classes/com/yape/antifraud/AntifraudApplication.class new file mode 100644 index 0000000000000000000000000000000000000000..436c1593d2e41808e7977e08213e86d758ecd930 GIT binary patch literal 752 zcma)4!E)0u5PeFMIx&Hk6jIv4ffGp%=+;X*oe7!YWS~Qs^w5*+sIH1FWn{U)XK{k* zp&!6UF|16O`rrcx?^?U7w{PF-*YDdq04I16pvCYiF**Mx){+bD)TI^WiqHQ2&DQHo zCBiAA1GE`-uf>hvnb0Z!5MRs0F>IeGt=uWY)@ZzBXwS_`hS)-{j}EpOb|R(a`!bKE z{UqW{G7KVeZJDp(t`k0*Faqu7#w<53NFo{6HEHg$@c;1i>r{Ob7J=u4HB z)=ygNLt&rxLkOGF+X$73JmBD*yJa6&+qStl<~Cz!Wu>wL+n%h8GRjk R2IN{esO%w*$osa>fj=SJ#KHgo literal 0 HcmV?d00001 diff --git a/antifraud/target/classes/com/yape/antifraud/kafka/AntiFraudListener.class b/antifraud/target/classes/com/yape/antifraud/kafka/AntiFraudListener.class new file mode 100644 index 0000000000000000000000000000000000000000..fd3e677d20ccb4de89298b1385dd31f4ee3cb6a1 GIT binary patch literal 1806 zcma)6+in|G6kW%TGq!Qs+#1s2Kw3)cOOh$20g6i?O%q7#G!cm`A)b!MC(bnXjCE#g zs1U!xE3ZX@6oJGm5?{hsAl4Z>uG?l%EP3YaGyAgk+Lyoo{ryh>_poOnAy9Jsw*6Fg zlr6o`J=C(>u#e^8v9#AIZyCAj2BGqlwlF3z`9$`l-I89@-mO1TPAHJ+bn7iQI8vJK zsrOfeSgLFfMSh z>U!#Nw_R8IK-ODIV7lr%vQ?AXHS*wcEIe`pfu;E9uaQ95lRGLr@*8_n%eD%YriYC0 zZD=J!)eu)*>xXQeN$IDM!;2v|++cRSleJvA)< za-ek2b;$1m-m&nuz^&Mt#^jU3BCZOgda~6e_w$8fHENr-43F&lZu5b1+_r30vMkxV zIb6qk#MWb-@L(vvO2 z#_TEL(P&xRz_Mw$6@i-rkfY!Gut#r-wJdJowuScv3b8O>8H^l0z#W!mFjXx6`5I~@ z#i*ZB%Cwfi?fCAFDWB<_AevS)H!lW$z%uC8Xn}Zi7ieRY3oR>4t!$~(;3@od`U=baqaia49=acC@?{m zoZ}tYi8g?R>Ps7~pP)c?-|uQiZMkN1%)Pb)R!n|o*PS(#+?87S;ZttZ4MO)lGvBz% zPEV315^6S-A&h4WX(W)Lw8eLV?`-Kg|K(pX@iV0aF7kOHvYfyePZ{1!@@}rLjVbyw zzii}HV20-uCyy`I0heex$MX!OH)%5e4Mc#;xDw#4D6T_QgKMEwK0*Ej*LF(3VB!zl z_?mKI={c58V804whNiQ~)4PGP*mp35vVc{5$aqHQBYe!L15m3}PMBfm)8t&Ip~*R4 z{tM&Ncb}DKQTYv@o?zogq^Ixxgw*sG&-gtVv5<{)=gHZX5eD+Zuz3R6X4r?cNF!-Y Yty_3>8hVkJ3G77A#}OmrRNV#s1JmNw|kH`X`~pY4)`HA9qzWxx6K1#DTeWAc3pHmhbzHQu1ddc2A*%b zZG!8HkJ9h-AT8+&^OZ(FonK+d)a|3xZ4lS~%+*9Pe;Me=I|ZA1E!4hjohd@VX)itwq)1`#9s{ga zY-DjC57Jm>Fo*Q1frog+FsII4y#0x)UHp5i4nw7*>Zlk_J}sn2Hk! zmykac`hhP*;#=UN%X^U?pHSHjK&DTU%oGpW>GF^*|oF?C?v*E?sHtfRq(dkrg7s($zNw7RirEx;hicX?xNr9gRk5 zOeT%`beX_Fs`q6a6BM0DP(v1`XDYxn%?3JzqOm4RKQL2TIYGX(dV+;-6iVU-wK)O- z#;Khq@Eifn;3h@x#mjIDw`oKGJu14VNhENGq6Y01e;cLVUFv5NG?8BPFalYOvH)Jv z2AW>3bW9YEv9R(TOY{`pYbuF|iUtMpL}WgqkdIfKQOKbTv$xF%{Q#ncPoj1WPwB0t HdItOjly%o? literal 0 HcmV?d00001 diff --git a/antifraud/target/classes/com/yape/antifraud/kafka/TransactionCreatedEvent.class b/antifraud/target/classes/com/yape/antifraud/kafka/TransactionCreatedEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..a6e0508a4bacd26a46844ec7a8319093ef1d3b55 GIT binary patch literal 2351 zcmbVMZEq7t5Pmk;@k=gsFiD!EX-Fv)+X)=d(l@72@&=}cB0y2qep;V5@x|vm_ih~# zsXwV7id3soKJ*9lM^&A|&5zUW%UfXE9|Pk^6j?v{J6=EBZDBm(Zl#920OufIezOszH-y} zCXGh|KTYg)<+0usHns8XsHK&M8d^DQH96`vG?r+r&{(ChCSX)tSNUNgDoBA!<;H;S z39rNNa}V8JZ0mvjH`b zJhu+oexHFI*{Ybg@|4>|&{OtBaM=a-xgX(sHtk zwYQ`@g?0K*6A1r5q5p%(7T548tw84-E}yT50Z)Yzhs^1$bAv-7lsL*Hu9LiwBmtxj z>VzCPCV{y{=Kl2jN8dlCdP$z*BNBpowJPc&H>HOa(GGWd)l zm_Yq-q^qMC*%-zwZca#UZPaAu+~hK~&wg?@$vyLtDxIMSj2elU(I#&7{KSoJ1HX^Z z7&p3$dp)B9d17kQrHwOu{w}Koz6=q+!q+s{ADD~g{bK8O&T6g5J4(5GoT(53Be-JK=!pL~!+ zV#0$zz#nD2v%Am@ZAkE8ckbN1=bStD-q}BYPksYfMMXo5!D!fBQ3PaNM3CUPBEmOW`m@f{-4SGsD4DmI)DKZ#=t|Nu33?s$TP8tk39SJ0r zHL62Hk~}rj67RikT{zpk-VrJryTLm<+%eTYbjD@NbQzXwmn;PxB)=(S%Wi(;4(|#& zG|`L|OM{6sq@*1jzd*&mt>Y#p7}krI)*MdW;%-aT#ji$HNlfXO#5BXoe@IlRG2*Mo zJ9M1!Xk$Lq_eDciN}rX&td1GXF>G93AyS|-N`}mq?KusxVX96|3?IKGHBD6aH?}QZ z8o6H305^j&7Bws|O!eo@@o1#G!U#0NNF5Kc#E`C^GB6xP&uCf)c3T)h^gC`fJHnl< z*>>CORU&zZvmEh+!0p4Hcq`n7WA>!&L?LS(?z&M&$nj;6B&uGCwmd9XE{ReK%M6o4 zuU#d$Upa;>J$VMbYFWbZ6A-S3XAE=wGF@m4D$%dEpq@^5QY_N90n_ARH8OjqK?l6k`~t9f5pm z=39z9hU;XfW8?;@fs_)sL2sorN2>}=lz$@ogN!JD+~<$^5N#+Ve;$%JgN)KuK2@0~ zTBV|uPjCx34`LC}B<_T%ML~Cg@8^<>f@W|p1Qkh1C7dcRoZ$XNs5l<@jPoecnkBq} fIK3a?F`i(Bd>Pt3#dEx*oL~7ds)njte$V~^_zrmg literal 0 HcmV?d00001 diff --git a/transaction/.classpath b/transaction/.classpath new file mode 100644 index 0000000000..c8ae32e9a3 --- /dev/null +++ b/transaction/.classpath @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/transaction/.project b/transaction/.project new file mode 100644 index 0000000000..a8d5578cd2 --- /dev/null +++ b/transaction/.project @@ -0,0 +1,23 @@ + + + transaction + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/transaction/.settings/org.eclipse.core.resources.prefs b/transaction/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..abdea9ac03 --- /dev/null +++ b/transaction/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding/=UTF-8 diff --git a/transaction/.settings/org.eclipse.jdt.core.prefs b/transaction/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..5b8827bcae --- /dev/null +++ b/transaction/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.methodParameters=generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=16 +org.eclipse.jdt.core.compiler.compliance=16 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=16 diff --git a/transaction/Dockerfile b/transaction/Dockerfile new file mode 100644 index 0000000000..e4f29becc8 --- /dev/null +++ b/transaction/Dockerfile @@ -0,0 +1,11 @@ +FROM maven:3.9.9-eclipse-temurin-17 AS build +WORKDIR /app +COPY pom.xml . +COPY src ./src +RUN mvn -q -DskipTests package + +FROM eclipse-temurin:17-jre +WORKDIR /app +COPY --from=build /app/target/transaction-service-0.0.1-SNAPSHOT.jar app.jar +EXPOSE 8080 +ENTRYPOINT ["java","-jar","/app/app.jar"] diff --git a/transaction/pom.xml b/transaction/pom.xml new file mode 100644 index 0000000000..2ec9eb64cc --- /dev/null +++ b/transaction/pom.xml @@ -0,0 +1,75 @@ + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.7 + + + + com.yape + transaction-service + 0.0.1-SNAPSHOT + transaction-service + + + 17 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.postgresql + postgresql + runtime + + + + org.springframework.kafka + spring-kafka + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.kafka + spring-kafka-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/transaction/src/main/java/com/yape/transactions/TransactionsApplication.java b/transaction/src/main/java/com/yape/transactions/TransactionsApplication.java new file mode 100644 index 0000000000..e44be8ba99 --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/TransactionsApplication.java @@ -0,0 +1,11 @@ +package com.yape.transactions; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class TransactionsApplication { + public static void main(String[] args) { + SpringApplication.run(TransactionsApplication.class, args); + } +} diff --git a/transaction/src/main/java/com/yape/transactions/api/ApiExceptionHandler.java b/transaction/src/main/java/com/yape/transactions/api/ApiExceptionHandler.java new file mode 100644 index 0000000000..c6a1836ba7 --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/api/ApiExceptionHandler.java @@ -0,0 +1,34 @@ +package com.yape.transactions.api; + +import com.yape.transactions.service.InvalidUuidException; +import com.yape.transactions.service.TransactionNotFoundException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.Map; + +@RestControllerAdvice +public class ApiExceptionHandler { + + @ExceptionHandler(TransactionNotFoundException.class) + public ResponseEntity> notFound(TransactionNotFoundException ex) { + return ResponseEntity.status(404).body(Map.of("error", ex.getMessage())); + } + + @ExceptionHandler(InvalidUuidException.class) + public ResponseEntity> invalidUuid(InvalidUuidException ex) { + return ResponseEntity.badRequest().body(Map.of("error", ex.getMessage())); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity> validation(MethodArgumentNotValidException ex) { + return ResponseEntity.badRequest().body(Map.of( + "error", "Validation error", + "details", ex.getBindingResult().getFieldErrors().stream() + .map(fe -> fe.getField() + ": " + fe.getDefaultMessage()) + .toList() + )); + } +} diff --git a/transaction/src/main/java/com/yape/transactions/api/TransactionController.java b/transaction/src/main/java/com/yape/transactions/api/TransactionController.java new file mode 100644 index 0000000000..86c627ffa5 --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/api/TransactionController.java @@ -0,0 +1,31 @@ +package com.yape.transactions.api; + +import com.yape.transactions.api.dto.CreateTransactionRequest; +import com.yape.transactions.api.dto.CreateTransactionResponse; +import com.yape.transactions.api.dto.TransactionResponse; +import com.yape.transactions.service.TransactionService; +import jakarta.validation.Valid; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/transactions") +public class TransactionController { + + private final TransactionService transactionService; + + public TransactionController(TransactionService transactionService) { + this.transactionService = transactionService; + } + + @PostMapping + public ResponseEntity create(@Valid @RequestBody CreateTransactionRequest request) { + String externalId = transactionService.createTransaction(request); + return ResponseEntity.status(201).body(new CreateTransactionResponse(externalId)); + } + + @GetMapping("/{transactionExternalId}") + public TransactionResponse get(@PathVariable String transactionExternalId) { + return transactionService.getTransaction(transactionExternalId); + } +} diff --git a/transaction/src/main/java/com/yape/transactions/api/dto/CreateTransactionRequest.java b/transaction/src/main/java/com/yape/transactions/api/dto/CreateTransactionRequest.java new file mode 100644 index 0000000000..42e273ddbf --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/api/dto/CreateTransactionRequest.java @@ -0,0 +1,14 @@ +package com.yape.transactions.api.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PositiveOrZero; +import java.math.BigDecimal; + +public record CreateTransactionRequest( + @NotBlank String accountExternalIdDebit, + @NotBlank String accountExternalIdCredit, + @JsonProperty("tranferTypeId") @NotNull Integer tranferTypeId, + @NotNull @PositiveOrZero BigDecimal value +) {} diff --git a/transaction/src/main/java/com/yape/transactions/api/dto/CreateTransactionResponse.java b/transaction/src/main/java/com/yape/transactions/api/dto/CreateTransactionResponse.java new file mode 100644 index 0000000000..fc85a68df4 --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/api/dto/CreateTransactionResponse.java @@ -0,0 +1,3 @@ +package com.yape.transactions.api.dto; + +public record CreateTransactionResponse(String transactionExternalId) {} diff --git a/transaction/src/main/java/com/yape/transactions/api/dto/TransactionResponse.java b/transaction/src/main/java/com/yape/transactions/api/dto/TransactionResponse.java new file mode 100644 index 0000000000..a3d423e9ca --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/api/dto/TransactionResponse.java @@ -0,0 +1,14 @@ +package com.yape.transactions.api.dto; + +import java.math.BigDecimal; +import java.time.Instant; + +public record TransactionResponse( + String transactionExternalId, + NamedDto transactionType, + NamedDto transactionStatus, + BigDecimal value, + Instant createdAt +) { + public record NamedDto(String name) {} +} diff --git a/transaction/src/main/java/com/yape/transactions/domain/TransactionEntity.java b/transaction/src/main/java/com/yape/transactions/domain/TransactionEntity.java new file mode 100644 index 0000000000..b27d5a46ea --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/domain/TransactionEntity.java @@ -0,0 +1,92 @@ +package com.yape.transactions.domain; + +import jakarta.persistence.*; +import java.math.BigDecimal; +import java.time.Instant; +import java.util.UUID; + +@Entity +@Table(name = "transactions") +public class TransactionEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "transaction_external_id", nullable = false, unique = true) + private UUID transactionExternalId; + + @Column(name = "account_external_id_debit", nullable = false) + private String accountExternalIdDebit; + + @Column(name = "account_external_id_credit", nullable = false) + private String accountExternalIdCredit; + + @Column(name = "tranfer_type_id", nullable = false) + private Integer tranferTypeId; + + @Column(nullable = false, precision = 18, scale = 2) + private BigDecimal value; + + @Column(nullable = false) + private String status; // pending | approved | rejected + + @Column(name = "created_at", nullable = false) + private Instant createdAt; + + protected TransactionEntity() {} + + public TransactionEntity( + UUID transactionExternalId, + String accountExternalIdDebit, + String accountExternalIdCredit, + Integer tranferTypeId, + BigDecimal value, + String status, + Instant createdAt + ) { + this.transactionExternalId = transactionExternalId; + this.accountExternalIdDebit = accountExternalIdDebit; + this.accountExternalIdCredit = accountExternalIdCredit; + this.tranferTypeId = tranferTypeId; + this.value = value; + this.status = status; + this.createdAt = createdAt; + } + + public Long getId() { + return id; + } + + public UUID getTransactionExternalId() { + return transactionExternalId; + } + + public String getAccountExternalIdDebit() { + return accountExternalIdDebit; + } + + public String getAccountExternalIdCredit() { + return accountExternalIdCredit; + } + + public Integer getTranferTypeId() { + return tranferTypeId; + } + + public BigDecimal getValue() { + return value; + } + + public String getStatus() { + return status; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setStatus(String status) { + this.status = status; + } +} diff --git a/transaction/src/main/java/com/yape/transactions/domain/TransactionRepository.java b/transaction/src/main/java/com/yape/transactions/domain/TransactionRepository.java new file mode 100644 index 0000000000..bb400c2383 --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/domain/TransactionRepository.java @@ -0,0 +1,9 @@ +package com.yape.transactions.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; +import java.util.UUID; + +public interface TransactionRepository extends JpaRepository { + Optional findByTransactionExternalId(UUID transactionExternalId); +} diff --git a/transaction/src/main/java/com/yape/transactions/kafka/TransactionCreatedEvent.java b/transaction/src/main/java/com/yape/transactions/kafka/TransactionCreatedEvent.java new file mode 100644 index 0000000000..873079d4ea --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/kafka/TransactionCreatedEvent.java @@ -0,0 +1,12 @@ +package com.yape.transactions.kafka; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; + +public record TransactionCreatedEvent( + String transactionExternalId, + String accountExternalIdDebit, + String accountExternalIdCredit, + @JsonProperty("tranferTypeId") Integer tranferTypeId, + BigDecimal value +) {} diff --git a/transaction/src/main/java/com/yape/transactions/kafka/TransactionEventsPublisher.java b/transaction/src/main/java/com/yape/transactions/kafka/TransactionEventsPublisher.java new file mode 100644 index 0000000000..9fc59bafd3 --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/kafka/TransactionEventsPublisher.java @@ -0,0 +1,24 @@ +package com.yape.transactions.kafka; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; + +@Component +public class TransactionEventsPublisher { + + private final KafkaTemplate kafkaTemplate; + private final String createdTopic; + + public TransactionEventsPublisher( + KafkaTemplate kafkaTemplate, + @Value("${app.topics.created}") String createdTopic + ) { + this.kafkaTemplate = kafkaTemplate; + this.createdTopic = createdTopic; + } + + public void publishCreated(TransactionCreatedEvent event) { + kafkaTemplate.send(createdTopic, event.transactionExternalId(), event); + } +} diff --git a/transaction/src/main/java/com/yape/transactions/kafka/TransactionStatusEvent.java b/transaction/src/main/java/com/yape/transactions/kafka/TransactionStatusEvent.java new file mode 100644 index 0000000000..cb37f25804 --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/kafka/TransactionStatusEvent.java @@ -0,0 +1,6 @@ +package com.yape.transactions.kafka; + +public record TransactionStatusEvent( + String transactionExternalId, + String status +) {} diff --git a/transaction/src/main/java/com/yape/transactions/kafka/TransactionStatusListener.java b/transaction/src/main/java/com/yape/transactions/kafka/TransactionStatusListener.java new file mode 100644 index 0000000000..a54b6bbfea --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/kafka/TransactionStatusListener.java @@ -0,0 +1,42 @@ +package com.yape.transactions.kafka; + +import com.yape.transactions.domain.TransactionRepository; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +import java.util.Locale; +import java.util.UUID; + +@Component +public class TransactionStatusListener { + + private final TransactionRepository repository; + + public TransactionStatusListener(TransactionRepository repository) { + this.repository = repository; + } + + @KafkaListener(topics = "${app.topics.status}", groupId = "transaction-service") + public void onStatus(TransactionStatusEvent event) { + UUID externalId; + try { + externalId = UUID.fromString(event.transactionExternalId()); + } catch (IllegalArgumentException ex) { + return; // ignore malformed event + } + + String normalized = event.status() == null ? null : event.status().toLowerCase(Locale.ROOT); + + if (normalized == null || (!normalized.equals("approved") && !normalized.equals("rejected") && !normalized.equals("pending"))) { + return; // ignore unknown status + } + + repository.findByTransactionExternalId(externalId).ifPresent(tx -> { + // idempotent-ish update + if (!normalized.equals(tx.getStatus())) { + tx.setStatus(normalized); + repository.save(tx); + } + }); + } +} diff --git a/transaction/src/main/java/com/yape/transactions/service/InvalidUuidException.java b/transaction/src/main/java/com/yape/transactions/service/InvalidUuidException.java new file mode 100644 index 0000000000..66b440557f --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/service/InvalidUuidException.java @@ -0,0 +1,7 @@ +package com.yape.transactions.service; + +public class InvalidUuidException extends RuntimeException { + public InvalidUuidException(String raw) { + super("Invalid UUID: " + raw); + } +} diff --git a/transaction/src/main/java/com/yape/transactions/service/TransactionNotFoundException.java b/transaction/src/main/java/com/yape/transactions/service/TransactionNotFoundException.java new file mode 100644 index 0000000000..af9c657dbf --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/service/TransactionNotFoundException.java @@ -0,0 +1,7 @@ +package com.yape.transactions.service; + +public class TransactionNotFoundException extends RuntimeException { + public TransactionNotFoundException(String externalId) { + super("Transaction not found: " + externalId); + } +} diff --git a/transaction/src/main/java/com/yape/transactions/service/TransactionService.java b/transaction/src/main/java/com/yape/transactions/service/TransactionService.java new file mode 100644 index 0000000000..618a6e03a0 --- /dev/null +++ b/transaction/src/main/java/com/yape/transactions/service/TransactionService.java @@ -0,0 +1,76 @@ +package com.yape.transactions.service; + +import com.yape.transactions.api.dto.CreateTransactionRequest; +import com.yape.transactions.api.dto.TransactionResponse; +import com.yape.transactions.domain.TransactionEntity; +import com.yape.transactions.domain.TransactionRepository; +import com.yape.transactions.kafka.TransactionCreatedEvent; +import com.yape.transactions.kafka.TransactionEventsPublisher; +import org.springframework.stereotype.Service; + +import java.time.Instant; +import java.util.UUID; + +@Service +public class TransactionService { + + private final TransactionRepository repository; + private final TransactionEventsPublisher publisher; + + public TransactionService(TransactionRepository repository, TransactionEventsPublisher publisher) { + this.repository = repository; + this.publisher = publisher; + } + + public String createTransaction(CreateTransactionRequest request) { + UUID externalId = UUID.randomUUID(); + + TransactionEntity entity = new TransactionEntity( + externalId, + request.accountExternalIdDebit(), + request.accountExternalIdCredit(), + request.tranferTypeId(), + request.value(), + "pending", + Instant.now() + ); + + repository.save(entity); + + // Emit event for anti-fraud validation + publisher.publishCreated(new TransactionCreatedEvent( + externalId.toString(), + request.accountExternalIdDebit(), + request.accountExternalIdCredit(), + request.tranferTypeId(), + request.value() + )); + + return externalId.toString(); + } + + public TransactionResponse getTransaction(String transactionExternalId) { + UUID id = parseUuid(transactionExternalId); + + TransactionEntity entity = repository.findByTransactionExternalId(id) + .orElseThrow(() -> new TransactionNotFoundException(transactionExternalId)); + + String typeName = "transferType-" + entity.getTranferTypeId(); + + return new TransactionResponse( + entity.getTransactionExternalId().toString(), + new TransactionResponse.NamedDto(typeName), + new TransactionResponse.NamedDto(entity.getStatus()), + entity.getValue(), + entity.getCreatedAt() + ); + } + + private UUID parseUuid(String raw) { + try { + return UUID.fromString(raw); + } catch (IllegalArgumentException ex) { + throw new InvalidUuidException(raw); + } + } +} diff --git a/transaction/src/main/resources/application.yml b/transaction/src/main/resources/application.yml new file mode 100644 index 0000000000..16d214df6b --- /dev/null +++ b/transaction/src/main/resources/application.yml @@ -0,0 +1,34 @@ +server: + port: 8080 + +spring: + datasource: + url: ${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/transactions} + username: ${SPRING_DATASOURCE_USERNAME:postgres} + password: ${SPRING_DATASOURCE_PASSWORD:postgres} + jpa: + hibernate: + ddl-auto: update + properties: + hibernate: + jdbc: + time_zone: UTC + + kafka: + bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:localhost:29092} + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer + consumer: + group-id: transaction-service + auto-offset-reset: earliest + key-deserializer: org.apache.kafka.common.serialization.StringDeserializer + value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer + properties: + spring.json.trusted.packages: "*" + spring.json.value.default.type: com.yape.transactions.kafka.TransactionStatusEvent + +app: + topics: + created: transactions.created + status: transactions.status diff --git a/transaction/target/classes/application.yml b/transaction/target/classes/application.yml new file mode 100644 index 0000000000..16d214df6b --- /dev/null +++ b/transaction/target/classes/application.yml @@ -0,0 +1,34 @@ +server: + port: 8080 + +spring: + datasource: + url: ${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/transactions} + username: ${SPRING_DATASOURCE_USERNAME:postgres} + password: ${SPRING_DATASOURCE_PASSWORD:postgres} + jpa: + hibernate: + ddl-auto: update + properties: + hibernate: + jdbc: + time_zone: UTC + + kafka: + bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:localhost:29092} + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer + consumer: + group-id: transaction-service + auto-offset-reset: earliest + key-deserializer: org.apache.kafka.common.serialization.StringDeserializer + value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer + properties: + spring.json.trusted.packages: "*" + spring.json.value.default.type: com.yape.transactions.kafka.TransactionStatusEvent + +app: + topics: + created: transactions.created + status: transactions.status diff --git a/transaction/target/classes/com/yape/transactions/TransactionsApplication.class b/transaction/target/classes/com/yape/transactions/TransactionsApplication.class new file mode 100644 index 0000000000000000000000000000000000000000..40c40032f5a1c30270afbec57f352c3ea85db9bc GIT binary patch literal 767 zcmb7C%TC)s6g?9X9NbVKyh;m;?m{G(9h)E|h{Vb*RfEz+S7S4n0edDIk9m9+E2=K| z06q$F#~|TFy6D39`ab5|bI;7v^WR4R``8N5VAx4a&hNxTa%Y7uMByw5qyHi`pnJZbdF{jJ@KqF^-R_WNpOY`; zUzJ0$z6@&kK(_PRKz^R0Ief$df%wCF6&TR&vi=_|{(3(jQpNWM2x}N^tYMw@ zKZ5=P1<&yVc>GKr@0+B_1g5mWk&}~|%$xV#{k{9Uza@YFd-E>MQ!bW}D6pUED zfRVc^qp|`mjvMs3p;Htnbxg9_m)-@dAdM6Ca~`R#svR@inRC68;g>zjDGht(sJ!TU z=ZujcC>zJ6UnVv3kP}$J7(r(ZS|!H}LXXF}`e0DIauN4oVA;liS*|`tt{4oI&DqL? zm~*oG_z_rgJfz*Da>(*665j2QF*EYDz@EfIUzB+xZ#hN7tj#rQL{;^`jb~mk?T`#~ z-4E?)EW#2Eiv>1JlYbpcv5dm=d5Vyl+1=4UZQrf!af@R;p=B4Pmu!q<0 zt2L}5Bgq1sj)Ziq!NUUSk_-l<@0%rZGryxV=9j9cW@8;TXjm^Wr@^T@I?ySQa)$+W zcEr|If-S+r)y*eVk)4fA*rH*x!1igf8D~VtRv3)oJV_GRn_$7TiKaYK@)9$~fDA_5 z;xSW2R3JV2YqsT3I9BmwXfbHdOcg%;_1QHI-c_((`F|1aJur7n5jTk^SMjn-$8J1M zrRB}yad|$JJ`?dSD(xP8o=qdGq~9g*=$)mXWDaeJd>Q2v0jnd?gjznSh@smng`?65 zn1hFu5bn*bzdb0ddw1}@`(vX8Jq)0TqKMyBQL1XeK>@8O1JknoH2QE@!xK!xNxq*h z@jCkPB(a#edYJcFO<3|mo2uG2iK^;eHyTzj1Lbf;!+^l%B#S0nr{gG&3CyJheU`L~ zhg4Q(vdB#2&nU&^EI%N^ah%XF$l3Mmsov-~3AP|C44yPc1(r3et&AE>!F-v`un~Gz z$0Nz+HC^+ljAGq zz`CQDk0VCn?TCi66GX*^tF<=`8;%A#sdEaI)IoH(s=T&LNFJ{D36k}^$DCM*qnxii>h&DYyAp8FSUvK>@s@Gw3d==9=PZ?Qz|JQZ~z#JkRX(DL&Wm znZTO5JXrnRbJEB~LgPepnEyOnZ%oG*_>$cL+k}ZBfq&wRR##Rwue725+MMg23(N7= zsOqa2?+pu2jFn}4`t)B`An&|3E~@Izy{2ssT7k^YYsM#2OR?JPwc_hE1isZ#!U$Jh zZpDaz-tRcl>$Oeam(>1`0_$#LHi;h%KMSiB%tq%(EFh}{J-;Ve2 yK6hxs2fU{6VRUvSk&pQNF~3S8UlHdUT)}tvo+BB~`vE`U7cAkwnMJtTJnKL1Ed=EN literal 0 HcmV?d00001 diff --git a/transaction/target/classes/com/yape/transactions/api/TransactionController.class b/transaction/target/classes/com/yape/transactions/api/TransactionController.class new file mode 100644 index 0000000000000000000000000000000000000000..f996d67e6f14697fb95cd1b720bb7108bb057002 GIT binary patch literal 2457 zcmcIlYi}Dx6g^`nUhFt&5@?$S0;Tj}C#Bm*`k+n%jY-lVr;U=x65<0I+k>;Ivuk$8 zDG}nY@Ebq^%0uEi{ZWWByNtmy`?1Az$+Rx*arq$E|;5JU{pRXZF6r@T82WT3i<~9 zTvhCfnMCbL7ImwJ76j-to;Z0SHglfIVrk!(1%5YsN3Aw3L^+&-XH zuXbF>;9Xp_@SecUVa1=t`?w@96)7bq0D;nfIKpnR?rI|)QoM|-7On_f8&FVLTtki; z4tOjriuplqb6_!EHfdRHIgOg~3l`=D?)Oj3EA$^}C4)S!o0|Sm;B1aZchZE~aplWn zuyM=6O@TWDMiyt6#ckYS|EQ3#z;YZRYI8$Xpyfwp%WMr_98tjwWYjloAFga{)=ZcB zSI7c$y*l4JZuZtsvaZ;kH{!vZr0X@bVgfvAFRY5if$MQY#maG%1=eCOnz6r)-4tt` z=)M!UH?ZezsrOHsby#qpWbp_O+2I*%j5cM`7mRt`^;&*atvjas&&Eu;H{A`BY;$=1 zl+>^PFiE;=&QuL!8XkDJdyV&8#{$_+*HwP8A%j4%{>EZ8#iqe4j#oMbV(vGNk{nxj z0|}%#Tjx8$cV_+tpM{?>{v&4zoZGkpKMp z3oQJG8wvct4H2zONZ~w9XF^IBBjXOGIV|EX@zUgR5BItIK?o!aA%olIy2zoxM|enh z!*PPM0-vQXAOb9hTrI(c6@D~4m+8vnD&6M!ahH>cj{(F|l8;3M`xVpNl-Lt!A_pbi=_w;W7E7;7UN8rBY)y!jAS7zu- zH;`6ndv0LLx@}fN&s_7B4AraFr)~9HLj_?L8G+FQc_d9ox_jofvOK>kFeNR^Yq;T) zx1sV~>6EMMYS#`0#w#u5m!WUFdnJMCZK~QewPOeNuA?5it{2KE0D&bM97;cw=8<&l zY9ux-#>O~pHw?^8FI=VXL*mS}ad1%)^C)rP0EaaA{A!Y4b`6V ziEmakOK)Vrq~6vX^FUgMf#;g?EMW6F&s)A%SAKX*i#`V3Py&Vjk;P`iacD9XyROM_ z-(0o#)|F+~r2b%j2xH3&?9e_^FZ|ca_h`|-V!L+uP+&{@Z`LTG{X$7I=kBpA?Fd|N z=Xy)}vZlyOTk$e$URCAMi^~SaaYdlFu(UG(ff)mR=+|$b8OX!IhTP1YP41ZhEn@oNgUi}zBx1rowW`tf}Z zs{*U%W?VFROXtM#=qt4izEU)ncAAR|Q$HFBV#)c8RdbPZmE5 zT)kM8Jr-zaXohu)jW4C8%wl?(Ld>@=*eGN|pRag3We<4W_^baWjeReWhiHx{RG6&UK<1Db!&U z64WkT5Cih5DeHut?}QyXgB|1KUu6E;>+F=sfAT>R zjR_C_0DqM6On0#>RUWWOXU>^D-}lYA%#WW(-vKP+iG>WqQ&)DJ10D)TD;`AL)t(F@ zhlifi($ZN~f@`tW|Fj{ZkOG8-EW_w7-{+3cgB@o>xKgzkCQ~#oKWd=@?$_yjywQ){ z)XEEXY7F^hFYxpVp~{1wE87g&RoN0n4B?y&3pT@0xw1VBhVwRZ$TO50ULe-Hou*J* zyy*)gBwg-rbLAO7In3&|7co3*oH1Lv>*$)$ZP|Lu74Hbji|8iGmBDK>6ts*p9H%;8 zvN4Iv3~S{xYyVxO&7-!dPOm0)BX!Nj6s|KY|A$nanj$`Qxlif+(UdpMUE%6l<(*Nw zX=56<7}n3Olq%eBYKG#b>?&8h@=PbE|2ce%W|pWW&!yB64O|%aCMsec6$@pCnf|n? zZlJx6aAKJx(nb{v48zT128P4*40^%7+!Ib5{h9|YUqrJFDfhZzEp_!|l2a!MaO)rx zFGS=jFVs?{A*()*qVz$+@qUmbtzJt{K~k|&9(M}Jl^8}C?0OIg)ngZtg(Zf$ehp4Z z$HGG@_35EB6mjlk#19=y^azJ&6zIX3mq=EQYzqZsFihSG?HSsO)o=7)_==H3@-isV znx{w*dX(0SaTLag$NY*tHiipi=NLIgB8LfD4ecE52Ar#Y!N_Ma1{sa&7(KdU$UMau zh*dozHJk*|81-ljXbM*noiykw@acq78Z?cW1XLy^qh6>k9O1@ks4Q;x7-uOVz$W}% bst3b8EW)9aBH8!x0FUTOkI65P->dR3k-Bf{ literal 0 HcmV?d00001 diff --git a/transaction/target/classes/com/yape/transactions/api/dto/TransactionResponse$NamedDto.class b/transaction/target/classes/com/yape/transactions/api/dto/TransactionResponse$NamedDto.class new file mode 100644 index 0000000000000000000000000000000000000000..1ac99cba52ffad5a366d6a4d04fbc07e7c7de9f4 GIT binary patch literal 1555 zcmbtUTTc@~7(G+iZmC-f2nt@n3rJg(1@BUVi4X%xMFhfwK25h1y3p>_-6;wG$p=X^ zCOr59{87elb{D%+(nM*}xqS1Tb7sCdvp;{G`~a|oMH4B8MMpO6Bi<6W^0^mqN4e4q zY~FJ1nv(WTC%7eo7A=XX4c-*BRV7XIGYszYLvA;?w`Xq&NBT8}evc9uhAW+=ZRNY( zUYQ}i(&YZO*yU8~)+FpgUcuP&yxPPZdIwRwXM`Pc2dtL_U&m5U#=*c}TK zxXbYVLSl&u{$XdxZp*gsh&Qgj)vVv%xAIy_6_8(B(e(sb%%EtZz%beIoZt48 z+Z1*r5NBE_VU}T_ddk3XoOGh=9m)e?N7-xKt2IP0RgvM`CzSDp98*;}qOCe8fnlgbL2C2OoWnqYT^e-E-F*bp$?y-;zfc1>Knm;#9$nAuS=ol5(aH9 zTlTtpv?(07%{>AYoKSEnnolLe^~6cKZDH5_NOE72M|RcqUAe~aXXWfMuEO|A*tnqS z3rFu{R^~;2TtlGVAB8R-%&6_AByAMnhF`;Z9nlSMm zwXEU#Vz=8q6yZKU^r)_-M&NMofQPPn?i(|*>>LKJAG zQaxLFhBY!@X<*8Oxam4lWd^TO!;qIjGQcJJfT|{L!(!N~T%1R3bXN#CO)zD6yF#|$@zq7ioexDiQ$zNbkF_6>c(hl2P={=IJc@KfKgLgI zgXr1+*Ykd@CbRe|k8f#+H1!&4XHByzKKgT_akW_CYNs+bN#6@yb99yITA*u@!L0kf z2xHzN%3+(~@#Q}qhWtQwbNHU&*053M)I5hBh8yR*(zGTGVwl(!k=zkVYiM?}$u9;E zNR7s6Vhxm(bkVM)gezW2w&ImUD_%*mXjS@k4U-td6g~Y)t3oYVe_`5M>0!pY)5Dx~ zw}-MdpXp)2nm2k_d`CWGxIyn-PaNjp`hvK-T~+lJJ2bFM>kG1H$hL)-v{N&aOl~r_$z6uoP(P0XfH5<^Uqex?Z+!V*GAN+=CrNSqRqf^l2=gAuk0o7%f{cbzE@ z(D!L)>gi0U(+B87WqPhw#)}cn^aox^_Z;1OkB&6_^Y+ibiD-$w%~HyunVR2pPQtg-+dX3fFTg-L-Wua-)+h^;X>sa6H1~z@~ z@UcaO?G|`VS#?AApdnX0&yR#kVbL|fe-uF^oMRb;ZWu|gCY^E}v|Gl|Q|ZY-M6zBL zjg|y#AVkrTJUn>^11(ifjuoR^THmUaE8kg^Pc*##b0h;#G|JsBT9Mmuc6ZAq=$ z3sFZBdhSGl8!M{O$qf7Tm@sy3r?o)Vd8=^~tEPjOx$qxkz#6dvR}y*49`uy~x*XD| z{RlACR{9N}0~(0&O%WYAtL|Y**4(COfO6?Lz&M2b-1vw^>98hZ6=1zg2rINgz)%Pu z>k10hx!E&L*#p9huu)DU_5~oBCD(JKWsCYICaX|?&9BQG_0hCV6EulJH(gI|wVDU$ zh(%{1edMi*z~#AK?2nFIB%j^VWt{4xuS5VB z;~GGd^r4K{2qP1diDJ~1<~>R_r74383|J-cLL@HHDYL5)9s}T4F7W!*GpSD9K5n9P zOg*ggC#;)4vrR{5+(1CptAVOJ5QATV+R>)8F-D?}FHbi$2cUuaRZd%lfo>E z+54Cc;LAstlQc*+7GNJ8&f_}-+HeTu$R1sxt9z6O1isRcVFgJsjs=5q2x*TL7q zH(mULrhda9MR)PbvJkeJ!LJOmb*D_Lu{fuC}$R) n)efUE>eP}MeI1{Go5ufK${{=Ix1yeyArN*kucAsk65sp_AjlvR literal 0 HcmV?d00001 diff --git a/transaction/target/classes/com/yape/transactions/domain/TransactionRepository.class b/transaction/target/classes/com/yape/transactions/domain/TransactionRepository.class new file mode 100644 index 0000000000000000000000000000000000000000..20f23bc2e0debabe3a7ffab3bfecf1a597f99e37 GIT binary patch literal 607 zcmbV~zfQw25XR4e5?cOcVSydNf+ZxTR1By^Dhev1RAN06H#j7=PMQOL7FL~`nLqVRM-_Hu)p9U zIjhR3U>^iM-eFj&|Jjmo48+2>GBrurCO2_Pi=ho7m!`IOtH*5r6zmc4dhS9&e`DY|Y rIFcf@h<1_$R_yB8pF-@keOLz%`Zn@l0Gsyg5!h(Mt#;r3x!m~znpVVs literal 0 HcmV?d00001 diff --git a/transaction/target/classes/com/yape/transactions/kafka/TransactionCreatedEvent.class b/transaction/target/classes/com/yape/transactions/kafka/TransactionCreatedEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..d23c1567735997e8cc8d2bd83ea31f4562981b2b GIT binary patch literal 2366 zcmbVMZEq7t5Pmk;@k=gsFiD8hG=#TeUjhfEw6soX$qV4rPy{Hd+E45ACcgN5=iZ$o zBK0TrLy>A#%7^}d{-~-mcXoV!0g0Tnx3jx5&&)hKJOBQ7`VW9jyhve6;J)d$j1$>b zM&L=umu6tOj&C&OK~oxU23y;nl7Xu49xEqEAt5k#B#)(GOXtvdrA*hW3oOJScHaid zbEI9N{d{$x`#SI}=ddiWC{5GtIKe=1N7bxA;PTi3`L6THEaM+2@6AbDG47=pZp8`I zq4Eg0@QP5amfE*`t7famj^hS0%u2wha=Hi7r{LbUY~x6pP2Y74d8TCS(fXz5wv`v0 z5L)tB+8ssVM!s4yXc$}8;f^w`mb6J>ded^O;E_PB7z?MD=11=IlbGzQv@dXNIJuY7 zlPyKb3}u@ zs+OZ(bXqmyToRXjm98o6ed$@e?rkQ5hUE)92+94(S|SGLo~xkY*3WVwsQF@PoH{D7 zq3u3f0!#h<@#{$kZgdxUDtcW*5$gh#;<-Yd7*o0-{RR^r(p+IThK3E?6?k|~Hx;TX z^;<{U#Kc0ps(z{+DKjXSeqk?PYPg370(_!F$nbG$JQGO%30Ho=m3JM-X@yPtplW+#z<9Z+cccaJ{(6wk>@>zR|<@H3mDudpUmhJ-%|&_$H0V z0zXged*!h{7B;x??Wnz#hnibCY&$vXJ2aMPEYnz_u_~Zd97lO!BFayJs^#W@?g_E? znM>hEvj4CuRbE6h2~k_8BBRQtdP^eD-Gih&_l|I;&JoVkH%M!Se^>s>7B8(l2vx4T%@3yCgP^g^nZQyp#Pu%DZ@W%*^aie?q zqGwbjPfTrEUq8kD4_PJfRfzaC9@0Ed_TSTW2>gI8Y-0zzc!H;N!d3eWd#Iv-=d|XM SiE2Em@Tk7IP`D1Ll>Y~lOC+lR literal 0 HcmV?d00001 diff --git a/transaction/target/classes/com/yape/transactions/kafka/TransactionEventsPublisher.class b/transaction/target/classes/com/yape/transactions/kafka/TransactionEventsPublisher.class new file mode 100644 index 0000000000000000000000000000000000000000..a8bc7f2266f6a38d9247aa6efe03d858f2643f20 GIT binary patch literal 1726 zcmb_d?M@Rx6g|@xO6&4fpx`HhsBOWn3L29V64OAURwdHZzfQM9S-Rcb?9PJ3_y)d= z325REAHat)-q|i6wU|)ikDZ;lJNMi(ch0^0>-UeJ09LV*M2z97;k5Mw?h0Lc-1fO4 zO~>~27T<1hy?Sa|-xIdw~Ut{>vAIkqb?fG=(-vzcb z+oERrX5A8-TwR_N-gDb_Bo9TxuyXFf>w<)&Z=&bye`ZLOorXvwj!6wyFvSqh2ba_ZWKYwU9eb<0L^8X2k83NhB+Zo4aV> zE+yt`Y23lxBo-K!FCk?O_i&%me5SJ3KhhoA+>z@7LzD2EcH{l8kX>Y zZq64rA%DpA0-v#Tn#I{Vh%6DGK$@0rIJOaZ9(5hP>`*%qQr+i9pjv~{kWdYY;mM^k z%aGo30?!Z|rqaypzZ+dqH5JlZcR6%bLE+pg@F~&4ktCFmzhe{K66Q#|acaLYWR#R? zl?+!yv?f7^b4H@qkchqvV}z_DF&aqj^o;o!r`z$f{AS&bJ|&&C)y-qmA^UhY`qJ zcnaVp1yJ-dg+ronh?&K2n5QTAUQvmKR1_$XB_h)yg>1*;ghB>I=uwyf`fY@c55w^h L9@AT;Y8m(g`pNRN literal 0 HcmV?d00001 diff --git a/transaction/target/classes/com/yape/transactions/kafka/TransactionStatusEvent.class b/transaction/target/classes/com/yape/transactions/kafka/TransactionStatusEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..26e000237bff18eef401125e73dcfea3689b4d05 GIT binary patch literal 1600 zcmbVMT~8B16g^YgZd=#3RPYPrLqXbttRRY7;)95xNl_z&2Ys5hBVF3=*4-(Q|Kx)t z5)&T$0sbiCo!y0QXwyUSi5u%84&Mn?>BWsU04 z5GPN?w8Xn^yDFSLUTq1Lja}odeeRfQA2_43VY&=!mH)2>oh7>?WW%n1;0|vKIyW(m zMJ#DpWSH*Fp3}9Y*%pSc5k%^Egk^?g^_+p>Bz#QMI@T0f6Rc{G*u43EG zZl@H=JDBT`Cjjmpcf=dv)*Q1VZ6^%bY;o5OI|7c+{Ul-aQn>L!xiWDS5?EoF9C!sw z{$0y3r0K~r=w-_ij+cONH9TXO@0DrDi8VZDm>M2R^Wv9>4FAu76}pfkG$j$_)cqtY zr*0>$ar%-#lD?#9w?nIn%M^d%T5<6d>EhBUvM1zHP(K_La)ay{KNMparyYSjYUWvr zJc65KCnMwrsezPYxJ7TJG*7DvjTL_){ez4!f7IiTco1zMBzqYWyMT<+ojzAtAX=rO z70+-7xC~+;&?N2!sf9sP!1qhZg+a5pAAs_tq!LaP7tiou7%GZ~9^(S?w5ADfAWHAY bSj7{pkuOENr&z}e%K4=iqiU$S<@M|z6wiOv literal 0 HcmV?d00001 diff --git a/transaction/target/classes/com/yape/transactions/kafka/TransactionStatusListener.class b/transaction/target/classes/com/yape/transactions/kafka/TransactionStatusListener.class new file mode 100644 index 0000000000000000000000000000000000000000..fc9e1c61f8f91fc1d40ea33df831ce9330351519 GIT binary patch literal 3101 zcmbVOTUQfT6#gb$CWN6-yi_aV4J|<+7PYpGwbh7~5Tj58Ai?fvp6 z`UiZbtEH_EeQek2>hI~3tE=CcNnlh$FAtfVbLQ-Q_P4)p?=!#u_2?G>=kbk>god+4 zrtA?ICVnt*uVOKIUi+5x( z(2(+^>-c8icxxKY0&zrUxT+ncC@c%eS7c{iyoRUnT1)T6wzjl2f`SJW-W_^yn<<*ikNb0NBLw_=>cHtOB@ywq^%rRTfO&WVjb?+aW)SIhA(D zt7LrFGwn)QoqNymmg|Iy&5fB!#c+d9mG;1K%_8l04?GaAI~q+#{gC%hH0Tx2sksv+ z4ZC7W8S$mJViuX~gE*w4U&Gk;r0)dDz+oKGuqWnse3jXOME^=M_R7$Zmr>iC3v166856vZM}q-9Q%S8MC}w6BY^F6Gt0WW;T5*36@mSld4cYyvfE2o$@F zl}k@di(#rYB;+cKAeN72k+2V>Y{#n#%e*gHdUajLw96e`>|e#@DdE<;WYQAV#gZ6c zIgH1pSFhA2>7JjkBc%YwT|+dnH0O^WwcV@bmwaenKTk@Ksd$ z|NYD8$enHD9klK_CoF5u3}m*u9e1CSLZe$2da#<}_re1M@8SJ!9rrbyZq|pIsgX+V z0dG!Y!saJa&Jw;aeH~wDINl@|PbN{vSCqugTiGY0jN=HyZDIdp(W-A8j#@a@kwgL= zoL%96g8!+ZANf1^1G?5ZOQ4(2=R(VFw4#T5pXU?U8|~&yb!FOxUU~a-+{TW@KVHq) zL({z+@8awQn(Vs`&BuPc=;J_m?w{Py$_)!AH_-PJj!r#9+w?jogTF!79->PPzXP8y zPmlbH{*m5u8+h$o>>cTSBOG*%^u8GmTGxlZN7wMrxR}7u$RoTBY+!Po2ZJa(ah)eA zG)FlDgGpi^42IH$K7K6pv$zi-$G10;4iR1mv$U{@Z~=3er?({i+(3a~x-eNE8C<`K z1-?1P%llp2;^;O{*@yN?9oHX2({U^{p=0c^`VJaX2?_Hw2lOPAi0DAkAn8`o)OT`t z10RIAb`2AJv5u{hz)eL=1f@4j-2lNIXUHd*(!m%xeVd{8VHp-ZtB^?h0h(1gOu!Dw fY3Jb%=PrK=$vtjb!^ij(pK(PA{d0VYud)AcKXr0x literal 0 HcmV?d00001 diff --git a/transaction/target/classes/com/yape/transactions/service/InvalidUuidException.class b/transaction/target/classes/com/yape/transactions/service/InvalidUuidException.class new file mode 100644 index 0000000000000000000000000000000000000000..7ef2f14f196fb64d506e8f6aa5f2d07c689bc49d GIT binary patch literal 625 zcmb7B%Sr=55Uk1D7+*1o8ej32D7qk?Oz_|fgeam$@Hp-cW@IxPCbLmL%S!?Zet;h( z_L!icxp?X6n(D454N+QCr?FKF9iMNGgG*=z&8X2gL(-FEWUE!RlF88I^ z2&H%Q=!&*wlZY`C?|GLyK38|nMW~EyiEo}EQIkrVJ%)U_{!@2pv{ZN1$~8mmAn-&I zV+?b@`TbD(p3o_bGfWQcOO3|K;ch976eco=BVn_t45l$dX1v`N%466ZW%kE^s9&`b zvl--&XGob~FdRd!T=~;NwNXqkOx2|lXJPAB=qrBf3x;exaJhfYwX}Hn88c1UVc4nv zf3;PHsOAq=`1f9jnm!e#8F=Sh^Oi6|lS%qA2(>GYrJZJB)U~#(5Y|A-bav3o>;@4* zlF%t)lmYqmSEO#T={_j z^<+2M%-K0J=j`mu>*F(kCTay_25-j9nUHtOPIbA*CI@Wz6cLf?NnQSn>H7&}{vG z)(t`+Z=AGRB)j~yO0OqEc~81a6CVgG+LF1f8626^Msi1abBjO5*z=of{sXWG;-~pV zym_$5pulJkS&o3}@)L@umEZxTm3s``qw;|9J5FRU!DsMJ%JC5Mm}ETuQG_W>Gvad0 TV3r%tahxLtUT2=q3>Mx14{NbL literal 0 HcmV?d00001 diff --git a/transaction/target/classes/com/yape/transactions/service/TransactionService.class b/transaction/target/classes/com/yape/transactions/service/TransactionService.class new file mode 100644 index 0000000000000000000000000000000000000000..b4b28ef8b1c4a5d6971fe47c14bf640fe06aa1d1 GIT binary patch literal 4745 zcmbVPX?qjb6@IU@W@K>F zHgrk%HeJ&t-O_z8X@d>8P5Ze||3Sa@cl7CdXGYS+%T2n{SvImVIaOJl43^?(5NN%wFY8HDx8{?V zXRphwCy;Pt!FCPLc2)#VW@?Mg*?HZtqEaWyr&0nfh2pGfxC_z|I8#T&qCU5%M2r09Yg&O7aP0oYA@GQdQp% zSm;oMvZ|6dU@<1&sKC>;m2Im3pek}c|ER3LsNs^zg=WtVG9-Z!yjLOmK7rY&0bv5w zgCUw^kv&^u+BKcP7%s;#UbhN1d9Z;xHC(~-tlN-Lk_HkZFE`SsR!6GSG4?DAURnq6imZsrg<1~EReP<=9V;QxQ<1E z?Y1*&x^im4QAAVH;TyMEV6=Ob3ouVI^~Fc3V5n%AIq5XR4q4O-?r?IarXS&h-W8o3rkAVXEnU6_^E}OCOzFNx@z_F z8or=um0z#WaYCW&go;h0;&Sj}D=laAyNQw7`Xv0p1N6~}*D!*^6gC*~YGANU=|ck4E&(sY)# z*vXBYVt~<`S?O100m8u= zI~e5b;+S3tC&^}0&(G%cjuQe`YJ{&I$(4MF5YV{oUErKl@r8}^XLXbGVFV=bI+h6Q zq+N8f@`9np;e8Q}lflc!afOsX`viwHPB+trYj9E?v@DzXtX^CMIy1I2pL7dq7@bpd z?+x2oOu8KCq^%;E3`G&3)*;*WTqZ;zn3Gu#zr!Em_n!)}%Gaq*o!3{-A?HcD)v z+F{)^Ck;=gb~WL*8)x5;4_k3tHMqZO_z8Z>eSZ-+&mpxo13XLuq*`%@e3P~;=?t5? z>q^G5xx`^{+!uJVQYKXZRU;e6-vkbAy_IAigaJ>`iEZqSF|?`oGv2kSw=-TF`J@F2 zKH1KHGrX#OySmq)b@$xiP46A-euGOfyoaOe<@0dow|!h$JTLprnhGmNBHgJw};*1!>S z3RkK52>LON7YL66piyvxa{m23)C%(d5Do>(wQf4`fidM^?>&4thMxPF1y(WlPaGa! zhdI+`t)bAj3U?LDtN7U2hIPC+!~dV4o9nnW)84R#PpccQeTKKZe2(8QuHh>c6#Ai2 z*(v70X|&=DeLYPq&eF;OzE_>&=R7WOEPEc$(f&c2IpBMGGBC32={3B9uhWqx`t}Xq z(}O$_c-l|IzR9NzC7)lR%9xrF!+;xv!_SwVyZF{^hWyo;o;7^$ACw24YQ*>XSf$%e zf7?Z_T%x9Qom6`*w4?<;#E+=r$2{2tF&d|w5cSu9)`Tizs!*tRQLs|hvX0khnCw5V zAjFe=aK_ga<6Q%O!QU8uiC^)mp8lHG-|(yP{?8Qj2Hs?x*0|EfeYZG2++{Z1!#e(s G_WuJ~9c&!{ literal 0 HcmV?d00001