From 4acf418d3f97373d1bed4068742e5527cae3f975 Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Tue, 20 Jan 2026 21:46:35 +0700 Subject: [PATCH 01/12] Add inspect user blocked shop --- pom.xml | 1 + .../fraudbusters/config/CachingConfig.java | 20 ++- .../handler/FraudInspectorHandler.java | 51 +++++++- src/main/resources/application.yml | 9 +- .../handler/FraudInspectorHandlerTest.java | 114 ++++++++++++++++-- 5 files changed, 181 insertions(+), 14 deletions(-) diff --git a/pom.xml b/pom.xml index ff03e523..8c5f199f 100644 --- a/pom.xml +++ b/pom.xml @@ -109,6 +109,7 @@ dev.vality damsel + 1.681-7a97267 io.opentelemetry diff --git a/src/main/java/dev/vality/fraudbusters/config/CachingConfig.java b/src/main/java/dev/vality/fraudbusters/config/CachingConfig.java index 1d8ddc87..c7458093 100644 --- a/src/main/java/dev/vality/fraudbusters/config/CachingConfig.java +++ b/src/main/java/dev/vality/fraudbusters/config/CachingConfig.java @@ -1,11 +1,13 @@ package dev.vality.fraudbusters.config; import com.github.benmanes.caffeine.cache.Caffeine; +import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.caffeine.CaffeineCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import java.util.concurrent.TimeUnit; @@ -13,13 +15,29 @@ @EnableCaching public class CachingConfig { + @Value("${cache.expire-after-access-seconds:100}") + private int expireAfterAccessSeconds; + @Value("${cache.inspect-user-expire-after-access-seconds:300}") + private int inspectUserExpireAfterAccessSeconds; + @Bean + @Primary public CacheManager cacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager("resolveCountry", "isNewShop"); cacheManager.setCaffeine(Caffeine.newBuilder() .initialCapacity(200) .maximumSize(500) - .expireAfterAccess(100, TimeUnit.SECONDS)); + .expireAfterAccess(expireAfterAccessSeconds, TimeUnit.SECONDS)); + return cacheManager; + } + + @Bean(name = "inspectUserCacheManager") + public CacheManager inspectUserCacheManager() { + CaffeineCacheManager cacheManager = new CaffeineCacheManager("inspectUser"); + cacheManager.setCaffeine(Caffeine.newBuilder() + .initialCapacity(100) + .maximumSize(1000) + .expireAfterAccess(inspectUserExpireAfterAccessSeconds, TimeUnit.SECONDS)); return cacheManager; } } diff --git a/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java index e66412b6..6f0e32e0 100644 --- a/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java +++ b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java @@ -2,9 +2,7 @@ import dev.vality.damsel.base.InvalidRequest; import dev.vality.damsel.domain.RiskScore; -import dev.vality.damsel.proxy_inspector.BlackListContext; -import dev.vality.damsel.proxy_inspector.Context; -import dev.vality.damsel.proxy_inspector.InspectorProxySrv; +import dev.vality.damsel.proxy_inspector.*; import dev.vality.damsel.wb_list.*; import dev.vality.fraudbusters.converter.CheckedResultToRiskScoreConverter; import dev.vality.fraudbusters.converter.ContextToFraudRequestConverter; @@ -13,11 +11,20 @@ import dev.vality.fraudbusters.domain.FraudResult; import dev.vality.fraudbusters.fraud.model.PaymentModel; import dev.vality.fraudbusters.stream.TemplateVisitor; +import dev.vality.fraudbusters.util.PaymentModelFactory; +import dev.vality.fraudbusters.util.UserCacheKeyUtil; +import dev.vality.fraudo.constant.ResultStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.thrift.TException; +import org.springframework.cache.annotation.Cacheable; import org.springframework.kafka.core.KafkaTemplate; +import java.util.AbstractMap; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + @Slf4j @RequiredArgsConstructor public class FraudInspectorHandler implements InspectorProxySrv.Iface { @@ -64,4 +71,42 @@ public boolean isBlacklisted(BlackListContext blackListContext) throws InvalidRe } } + @Override + @Cacheable( + cacheManager = "inspectUserCacheManager", + cacheNames = "inspectUser", + key = "#root.target.buildInspectUserCacheKey(#context)" + ) + public BlockedShops inspectUser(InspectUserContext context) throws InvalidRequest, TException { + if (context == null || context.getShopList() == null || context.getShopList().isEmpty()) { + return new BlockedShops().setShopList(Collections.emptyList()); + } + try { + List blockedShops = context.getShopList().parallelStream() + .map(shopContext -> { + PaymentModel paymentModel = PaymentModelFactory.buildPaymentModel(context, shopContext); + CheckedResultModel result = templateVisitor.visit(paymentModel); + return new AbstractMap.SimpleEntry<>(shopContext, result); + }) + .filter(entry -> isDeclineResult(entry.getValue())) + .map(AbstractMap.SimpleEntry::getKey) + .collect(Collectors.toList()); + return new BlockedShops().setShopList(blockedShops); + } catch (Exception e) { + log.warn("FraudInspectorHandler error when inspectUser e: ", e); + return new BlockedShops().setShopList(Collections.emptyList()); + } + } + + public String buildInspectUserCacheKey(InspectUserContext context) { + return UserCacheKeyUtil.buildInspectUserCacheKey(context); + } + + private static boolean isDeclineResult(CheckedResultModel result) { + return result != null + && result.getResultModel() != null + && (ResultStatus.DECLINE.equals(result.getResultModel().getResultStatus())) + || ResultStatus.DECLINE_AND_NOTIFY.equals(result.getResultModel().getResultStatus()); + } + } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6a26aa12..7310363b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -35,8 +35,8 @@ spring: reconnect.backoff.max.ms: 3000 retry.backoff.ms: 1000 ssl: - keystore-location: src/main/resources/cert/kenny-k.struzhkin.p12 - keystore-password: kenny + key-store-location: src/main/resources/cert/kenny-k.struzhkin.p12 + key-store-password: kenny key-password: kenny trust-store-password: kenny12 trust-store-location: src/main/resources/cert/truststore.p12 @@ -46,9 +46,12 @@ spring: ansi: enabled: always cache: - cache-names: resolveCountry + cache-names: resolveCountry,isNewShop,inspectUser caffeine: spec: maximumSize=500,expireAfterAccess=100s +cache: + expire-after-access-seconds: 100 + inspect-user-expire-after-access-seconds: 300 kafka: historical.listener: diff --git a/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java index fb45bb04..033f4ef0 100644 --- a/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java +++ b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java @@ -1,40 +1,76 @@ package dev.vality.fraudbusters.resource.payment.handler; +import dev.vality.damsel.domain.Category; +import dev.vality.damsel.domain.ContactInfo; +import dev.vality.damsel.domain.PartyConfigRef; +import dev.vality.damsel.domain.ShopConfigRef; import dev.vality.damsel.proxy_inspector.BlackListContext; +import dev.vality.damsel.proxy_inspector.BlockedShops; +import dev.vality.damsel.proxy_inspector.InspectUserContext; +import dev.vality.damsel.proxy_inspector.InspectorProxySrv; +import dev.vality.damsel.proxy_inspector.Party; +import dev.vality.damsel.proxy_inspector.Shop; +import dev.vality.damsel.proxy_inspector.ShopContext; +import dev.vality.damsel.domain.ShopLocation; import dev.vality.damsel.wb_list.ListNotFound; import dev.vality.damsel.wb_list.WbListServiceSrv; import dev.vality.fraudbusters.converter.CheckedResultToRiskScoreConverter; import dev.vality.fraudbusters.converter.ContextToFraudRequestConverter; import dev.vality.fraudbusters.domain.CheckedResultModel; +import dev.vality.fraudbusters.domain.ConcreteResultModel; import dev.vality.fraudbusters.domain.FraudResult; import dev.vality.fraudbusters.fraud.model.PaymentModel; import dev.vality.fraudbusters.stream.TemplateVisitor; +import dev.vality.fraudo.constant.ResultStatus; import org.apache.thrift.TException; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.boot.test.mock.mockito.MockBean; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.junit.jupiter.SpringExtension; +import java.util.ArrayList; +import java.util.List; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith({MockitoExtension.class, SpringExtension.class}) class FraudInspectorHandlerTest { - @MockBean + @MockitoBean CheckedResultToRiskScoreConverter checkedResultToRiskScoreConverter; - @MockBean + @MockitoBean ContextToFraudRequestConverter requestConverter; - @MockBean + @MockitoBean TemplateVisitor templateVisitor; - @MockBean + @MockitoBean KafkaTemplate kafkaFraudResultTemplate; - @MockBean + @MockitoBean WbListServiceSrv.Iface wbListServiceSrv; + @BeforeEach + void setUp() { + Mockito.reset( + checkedResultToRiskScoreConverter, + requestConverter, + templateVisitor, + kafkaFraudResultTemplate, + wbListServiceSrv + ); + } + @Test void isExistInBlackList() throws TException { FraudInspectorHandler fraudInspectorHandler = new FraudInspectorHandler( @@ -59,6 +95,39 @@ void isExistInBlackList() throws TException { assertEquals(false, existInBlackList); } + @Test + void inspectUserShopsBlocked() throws TException { + FraudInspectorHandler fraudInspectorHandler = new FraudInspectorHandler( + "test", + checkedResultToRiskScoreConverter, + requestConverter, + templateVisitor, + kafkaFraudResultTemplate, + wbListServiceSrv + ); + + when(templateVisitor.visit(any())).thenAnswer(invocation -> { + PaymentModel model = invocation.getArgument(0); + if (model != null && "shop_1".equals(model.getShopId())) { + return createCheckedResult(ResultStatus.DECLINE); + } + return createCheckedResult(ResultStatus.THREE_DS); + }); + + BlockedShops blockedShops = fraudInspectorHandler.inspectUser(createInspectUserContext()); + + assertEquals(1, blockedShops.getShopListSize()); + assertEquals("shop_1", blockedShops.getShopList().get(0).getShop().getShopRef().getId()); + + ArgumentCaptor captor = ArgumentCaptor.forClass(PaymentModel.class); + verify(templateVisitor, times(2)).visit(captor.capture()); + for (PaymentModel model : captor.getAllValues()) { + assertEquals("party_1", model.getPartyId()); + assertEquals("user@email.com", model.getEmail()); + assertEquals("79990001122", model.getPhone()); + } + } + private static BlackListContext createBlackListContext() { return new BlackListContext() .setValue("test") @@ -66,4 +135,35 @@ private static BlackListContext createBlackListContext() { .setFirstId("test_id") .setSecondId("test_sec_id"); } -} \ No newline at end of file + + private static InspectUserContext createInspectUserContext() { + ContactInfo contactInfo = new ContactInfo(); + contactInfo.setEmail("User@Email.Com"); + contactInfo.setPhoneNumber("79990001122"); + return new InspectUserContext() + .setUserInfo(contactInfo) + .setShopList(List.of( + createShopContext("party_1", "shop_1"), + createShopContext("party_1", "shop_2") + )); + } + + private static ShopContext createShopContext(String partyId, String shopId) { + ShopLocation location = new ShopLocation(); + location.setUrl("http://example.com"); + return new ShopContext() + .setParty(new Party(new PartyConfigRef(partyId))) + .setShop(new Shop( + new ShopConfigRef(shopId), + new Category("category", "category"), + "shop-name", + location + )); + } + + private static CheckedResultModel createCheckedResult(ResultStatus status) { + CheckedResultModel checkedResultModel = new CheckedResultModel(); + checkedResultModel.setResultModel(new ConcreteResultModel(status, null, null)); + return checkedResultModel; + } +} From 8a37a51d8b12f06c3a2e737b245c926bf218633f Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Tue, 20 Jan 2026 21:54:50 +0700 Subject: [PATCH 02/12] Add inspect user blocked shop --- .gitignore | 1 + .../util/PaymentModelFactory.java | 34 ++++++++++++++ .../fraudbusters/util/UserCacheKeyUtil.java | 47 +++++++++++++++++++ .../handler/FraudInspectorHandlerTest.java | 19 ++------ 4 files changed, 86 insertions(+), 15 deletions(-) create mode 100644 src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java create mode 100644 src/main/java/dev/vality/fraudbusters/util/UserCacheKeyUtil.java diff --git a/.gitignore b/.gitignore index 4388c0f2..44e0668d 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,4 @@ target # Target ant folder build /tmp/ +/.vscode/ diff --git a/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java b/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java new file mode 100644 index 00000000..87c5aafe --- /dev/null +++ b/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java @@ -0,0 +1,34 @@ +package dev.vality.fraudbusters.util; + +import dev.vality.damsel.proxy_inspector.InspectUserContext; +import dev.vality.damsel.proxy_inspector.ShopContext; +import dev.vality.fraudbusters.constant.ClickhouseUtilsValue; +import dev.vality.fraudbusters.fraud.model.PaymentModel; +import org.springframework.util.StringUtils; + +public class PaymentModelFactory { + + public static PaymentModel buildPaymentModel(InspectUserContext context, ShopContext shopContext) { + PaymentModel paymentModel = new PaymentModel(); + paymentModel.setPartyId(shopContext.getParty().getPartyRef().getId()); + paymentModel.setShopId(shopContext.getShop().getShopRef().getId()); + paymentModel.setTimestamp(System.currentTimeMillis()); + if (context.getUserInfo() != null) { + paymentModel.setEmail( + context.getUserInfo().isSetEmail() && StringUtils.hasLength(context.getUserInfo().getEmail()) + ? context.getUserInfo().getEmail().toLowerCase() + : ClickhouseUtilsValue.UNKNOWN); + paymentModel.setPhone( + context.getUserInfo().isSetPhoneNumber() + && StringUtils.hasLength(context.getUserInfo().getPhoneNumber()) + ? context.getUserInfo().getPhoneNumber() + : ClickhouseUtilsValue.UNKNOWN + ); + } else { + paymentModel.setEmail(ClickhouseUtilsValue.UNKNOWN); + paymentModel.setPhone(ClickhouseUtilsValue.UNKNOWN); + } + return paymentModel; + } +} + diff --git a/src/main/java/dev/vality/fraudbusters/util/UserCacheKeyUtil.java b/src/main/java/dev/vality/fraudbusters/util/UserCacheKeyUtil.java new file mode 100644 index 00000000..6a540529 --- /dev/null +++ b/src/main/java/dev/vality/fraudbusters/util/UserCacheKeyUtil.java @@ -0,0 +1,47 @@ +package dev.vality.fraudbusters.util; + +import dev.vality.damsel.proxy_inspector.InspectUserContext; +import dev.vality.damsel.proxy_inspector.ShopContext; +import dev.vality.fraudbusters.constant.ClickhouseUtilsValue; +import org.springframework.util.StringUtils; + +import java.util.Comparator; +import java.util.stream.Collectors; + +public class UserCacheKeyUtil { + + public static String buildInspectUserCacheKey(InspectUserContext context) { + if (context == null) { + return "null"; + } + String email = ClickhouseUtilsValue.UNKNOWN; + String phone = ClickhouseUtilsValue.UNKNOWN; + if (context.getUserInfo() != null) { + email = context.getUserInfo().isSetEmail() && StringUtils.hasLength(context.getUserInfo().getEmail()) + ? context.getUserInfo().getEmail().toLowerCase() + : ClickhouseUtilsValue.UNKNOWN; + phone = context.getUserInfo().isSetPhoneNumber() + && StringUtils.hasLength(context.getUserInfo().getPhoneNumber()) + ? context.getUserInfo().getPhoneNumber() + : ClickhouseUtilsValue.UNKNOWN; + } + if (context.getShopList() == null || context.getShopList().isEmpty()) { + return email + "|" + phone + "|"; + } + String shopsKey = context.getShopList().stream() + .map(UserCacheKeyUtil::buildShopKey) + .sorted(Comparator.naturalOrder()) + .collect(Collectors.joining(",")); + return email + "|" + phone + "|" + shopsKey; + } + + private static String buildShopKey(ShopContext shopContext) { + if (shopContext == null || shopContext.getParty() == null || shopContext.getShop() == null) { + return ClickhouseUtilsValue.UNKNOWN; + } + String partyId = shopContext.getParty().getPartyRef().getId(); + String shopId = shopContext.getShop().getShopRef().getId(); + return partyId + ":" + shopId; + } +} + diff --git a/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java index 033f4ef0..354be067 100644 --- a/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java +++ b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java @@ -60,17 +60,6 @@ class FraudInspectorHandlerTest { @MockitoBean WbListServiceSrv.Iface wbListServiceSrv; - @BeforeEach - void setUp() { - Mockito.reset( - checkedResultToRiskScoreConverter, - requestConverter, - templateVisitor, - kafkaFraudResultTemplate, - wbListServiceSrv - ); - } - @Test void isExistInBlackList() throws TException { FraudInspectorHandler fraudInspectorHandler = new FraudInspectorHandler( @@ -128,7 +117,7 @@ void inspectUserShopsBlocked() throws TException { } } - private static BlackListContext createBlackListContext() { + private BlackListContext createBlackListContext() { return new BlackListContext() .setValue("test") .setFieldName("field_test") @@ -136,7 +125,7 @@ private static BlackListContext createBlackListContext() { .setSecondId("test_sec_id"); } - private static InspectUserContext createInspectUserContext() { + private InspectUserContext createInspectUserContext() { ContactInfo contactInfo = new ContactInfo(); contactInfo.setEmail("User@Email.Com"); contactInfo.setPhoneNumber("79990001122"); @@ -148,7 +137,7 @@ private static InspectUserContext createInspectUserContext() { )); } - private static ShopContext createShopContext(String partyId, String shopId) { + private ShopContext createShopContext(String partyId, String shopId) { ShopLocation location = new ShopLocation(); location.setUrl("http://example.com"); return new ShopContext() @@ -161,7 +150,7 @@ private static ShopContext createShopContext(String partyId, String shopId) { )); } - private static CheckedResultModel createCheckedResult(ResultStatus status) { + private CheckedResultModel createCheckedResult(ResultStatus status) { CheckedResultModel checkedResultModel = new CheckedResultModel(); checkedResultModel.setResultModel(new ConcreteResultModel(status, null, null)); return checkedResultModel; From be1d733fb532da001414fe8b7acd7e29d1c3b096 Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Wed, 21 Jan 2026 16:31:09 +0700 Subject: [PATCH 03/12] Fix status --- .../resource/payment/handler/FraudInspectorHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java index 6f0e32e0..4524234a 100644 --- a/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java +++ b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java @@ -82,7 +82,7 @@ public BlockedShops inspectUser(InspectUserContext context) throws InvalidReques return new BlockedShops().setShopList(Collections.emptyList()); } try { - List blockedShops = context.getShopList().parallelStream() + List blockedShops = context.getShopList().stream() .map(shopContext -> { PaymentModel paymentModel = PaymentModelFactory.buildPaymentModel(context, shopContext); CheckedResultModel result = templateVisitor.visit(paymentModel); @@ -105,8 +105,8 @@ public String buildInspectUserCacheKey(InspectUserContext context) { private static boolean isDeclineResult(CheckedResultModel result) { return result != null && result.getResultModel() != null - && (ResultStatus.DECLINE.equals(result.getResultModel().getResultStatus())) - || ResultStatus.DECLINE_AND_NOTIFY.equals(result.getResultModel().getResultStatus()); + && (ResultStatus.DECLINE.equals(result.getResultModel().getResultStatus()) + || ResultStatus.DECLINE_AND_NOTIFY.equals(result.getResultModel().getResultStatus())); } } From fce5358e71285fba04b032dce7019b563c35c74e Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Wed, 21 Jan 2026 21:02:00 +0700 Subject: [PATCH 04/12] Fix after review --- .../resource/payment/handler/FraudInspectorHandler.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java index 4524234a..fca898fe 100644 --- a/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java +++ b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java @@ -19,6 +19,7 @@ import org.apache.thrift.TException; import org.springframework.cache.annotation.Cacheable; import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.util.CollectionUtils; import java.util.AbstractMap; import java.util.Collections; @@ -78,7 +79,8 @@ public boolean isBlacklisted(BlackListContext blackListContext) throws InvalidRe key = "#root.target.buildInspectUserCacheKey(#context)" ) public BlockedShops inspectUser(InspectUserContext context) throws InvalidRequest, TException { - if (context == null || context.getShopList() == null || context.getShopList().isEmpty()) { + if (CollectionUtils.isEmpty(context.getShopList())) { + log.warn("FraudInspectorHandler inspectUser with empty shopList: {}", context); return new BlockedShops().setShopList(Collections.emptyList()); } try { @@ -91,6 +93,7 @@ public BlockedShops inspectUser(InspectUserContext context) throws InvalidReques .filter(entry -> isDeclineResult(entry.getValue())) .map(AbstractMap.SimpleEntry::getKey) .collect(Collectors.toList()); + log.debug("FraudInspectorHandler inspectUser result blockedShops: {}", blockedShops); return new BlockedShops().setShopList(blockedShops); } catch (Exception e) { log.warn("FraudInspectorHandler error when inspectUser e: ", e); @@ -106,7 +109,7 @@ private static boolean isDeclineResult(CheckedResultModel result) { return result != null && result.getResultModel() != null && (ResultStatus.DECLINE.equals(result.getResultModel().getResultStatus()) - || ResultStatus.DECLINE_AND_NOTIFY.equals(result.getResultModel().getResultStatus())); + || ResultStatus.DECLINE_AND_NOTIFY.equals(result.getResultModel().getResultStatus())); } } From 83a7c38a1a4b117a88c173ed9ac8b72f47ce3972 Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Thu, 29 Jan 2026 18:32:04 +0300 Subject: [PATCH 05/12] Change iface for inspect user --- pom.xml | 2 +- .../payment/InspectorServiceServlet.java | 29 ++++++++ .../handler/FraudInspectorHandler.java | 48 +------------ .../payment/handler/InspectorHandler.java | 69 +++++++++++++++++++ .../util/PaymentModelFactory.java | 24 +++---- 5 files changed, 110 insertions(+), 62 deletions(-) create mode 100644 src/main/java/dev/vality/fraudbusters/resource/payment/InspectorServiceServlet.java create mode 100644 src/main/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandler.java diff --git a/pom.xml b/pom.xml index 8c5f199f..21fe39c5 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ UTF-8 1.0.7 0.3.1 - 1.112-e9d16e0 + 1.121-c3e5076 1.7-6d29f86 1.44-5dbd6d4 21.12.0 diff --git a/src/main/java/dev/vality/fraudbusters/resource/payment/InspectorServiceServlet.java b/src/main/java/dev/vality/fraudbusters/resource/payment/InspectorServiceServlet.java new file mode 100644 index 00000000..c1d31133 --- /dev/null +++ b/src/main/java/dev/vality/fraudbusters/resource/payment/InspectorServiceServlet.java @@ -0,0 +1,29 @@ +package dev.vality.fraudbusters.resource.payment; + +import dev.vality.damsel.fraudbusters.InspectorServiceSrv; +import dev.vality.woody.thrift.impl.http.THServiceBuilder; +import jakarta.servlet.*; +import jakarta.servlet.annotation.WebServlet; +import lombok.RequiredArgsConstructor; + +import java.io.IOException; + +@WebServlet("/inspector/v1/") +@RequiredArgsConstructor +public class InspectorServiceServlet extends GenericServlet { + + private final InspectorServiceSrv.Iface inspectorServiceHandler; + private Servlet thriftServlet; + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + thriftServlet = new THServiceBuilder() + .build(InspectorServiceSrv.Iface.class, inspectorServiceHandler); + } + + @Override + public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { + thriftServlet.service(req, res); + } +} diff --git a/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java index fca898fe..1acf00c7 100644 --- a/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java +++ b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandler.java @@ -11,20 +11,10 @@ import dev.vality.fraudbusters.domain.FraudResult; import dev.vality.fraudbusters.fraud.model.PaymentModel; import dev.vality.fraudbusters.stream.TemplateVisitor; -import dev.vality.fraudbusters.util.PaymentModelFactory; -import dev.vality.fraudbusters.util.UserCacheKeyUtil; -import dev.vality.fraudo.constant.ResultStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.thrift.TException; -import org.springframework.cache.annotation.Cacheable; import org.springframework.kafka.core.KafkaTemplate; -import org.springframework.util.CollectionUtils; - -import java.util.AbstractMap; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; @Slf4j @RequiredArgsConstructor @@ -73,43 +63,7 @@ public boolean isBlacklisted(BlackListContext blackListContext) throws InvalidRe } @Override - @Cacheable( - cacheManager = "inspectUserCacheManager", - cacheNames = "inspectUser", - key = "#root.target.buildInspectUserCacheKey(#context)" - ) public BlockedShops inspectUser(InspectUserContext context) throws InvalidRequest, TException { - if (CollectionUtils.isEmpty(context.getShopList())) { - log.warn("FraudInspectorHandler inspectUser with empty shopList: {}", context); - return new BlockedShops().setShopList(Collections.emptyList()); - } - try { - List blockedShops = context.getShopList().stream() - .map(shopContext -> { - PaymentModel paymentModel = PaymentModelFactory.buildPaymentModel(context, shopContext); - CheckedResultModel result = templateVisitor.visit(paymentModel); - return new AbstractMap.SimpleEntry<>(shopContext, result); - }) - .filter(entry -> isDeclineResult(entry.getValue())) - .map(AbstractMap.SimpleEntry::getKey) - .collect(Collectors.toList()); - log.debug("FraudInspectorHandler inspectUser result blockedShops: {}", blockedShops); - return new BlockedShops().setShopList(blockedShops); - } catch (Exception e) { - log.warn("FraudInspectorHandler error when inspectUser e: ", e); - return new BlockedShops().setShopList(Collections.emptyList()); - } + throw new UnsupportedOperationException(); } - - public String buildInspectUserCacheKey(InspectUserContext context) { - return UserCacheKeyUtil.buildInspectUserCacheKey(context); - } - - private static boolean isDeclineResult(CheckedResultModel result) { - return result != null - && result.getResultModel() != null - && (ResultStatus.DECLINE.equals(result.getResultModel().getResultStatus()) - || ResultStatus.DECLINE_AND_NOTIFY.equals(result.getResultModel().getResultStatus())); - } - } diff --git a/src/main/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandler.java b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandler.java new file mode 100644 index 00000000..533d03ac --- /dev/null +++ b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandler.java @@ -0,0 +1,69 @@ +package dev.vality.fraudbusters.resource.payment.handler; + +import dev.vality.damsel.base.InvalidRequest; +import dev.vality.damsel.fraudbusters.BlockedShops; +import dev.vality.damsel.fraudbusters.InspectUserContext; +import dev.vality.damsel.fraudbusters.InspectorServiceSrv; +import dev.vality.damsel.fraudbusters.ShopContext; +import dev.vality.fraudbusters.domain.CheckedResultModel; +import dev.vality.fraudbusters.fraud.model.PaymentModel; +import dev.vality.fraudbusters.stream.TemplateVisitor; +import dev.vality.fraudbusters.util.PaymentModelFactory; +import dev.vality.fraudo.constant.ResultStatus; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.thrift.TException; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.AbstractMap; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class InspectorHandler implements InspectorServiceSrv.Iface { + + private final TemplateVisitor templateVisitor; + + @Override + @Cacheable( + cacheManager = "inspectUserCacheManager", + cacheNames = "inspectUser", + key = "#root.target.buildInspectUserCacheKey(#context)" + ) + public BlockedShops inspectUserShops(InspectUserContext context) throws InvalidRequest, TException { + if (CollectionUtils.isEmpty(context.getShopList())) { + log.warn("FraudInspectorHandler inspectUser with empty shopList: {}", context); + return new BlockedShops().setShopList(Collections.emptyList()); + } + try { + List blockedShops = context.getShopList().stream() + .map(shopContext -> { + PaymentModel paymentModel = PaymentModelFactory.buildPaymentModel(context, shopContext); + CheckedResultModel result = templateVisitor.visit(paymentModel); + return new AbstractMap.SimpleEntry<>(shopContext, result); + }) + .filter(entry -> isDeclineResult(entry.getValue())) + .map(AbstractMap.SimpleEntry::getKey) + .collect(Collectors.toList()); + log.debug("FraudInspectorHandler inspectUser result blockedShops: {}", blockedShops); + return new BlockedShops().setShopList(blockedShops); + } catch (Exception e) { + log.warn("FraudInspectorHandler error when inspectUser e: ", e); + return new BlockedShops().setShopList(Collections.emptyList()); + } + } + + private static boolean isDeclineResult(CheckedResultModel result) { + return result != null + && result.getResultModel() != null + && (ResultStatus.DECLINE.equals(result.getResultModel().getResultStatus()) + || ResultStatus.DECLINE_AND_NOTIFY.equals(result.getResultModel().getResultStatus())); + } + + +} diff --git a/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java b/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java index 87c5aafe..23f799df 100644 --- a/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java +++ b/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java @@ -1,28 +1,24 @@ package dev.vality.fraudbusters.util; -import dev.vality.damsel.proxy_inspector.InspectUserContext; -import dev.vality.damsel.proxy_inspector.ShopContext; +import dev.vality.damsel.fraudbusters.InspectUserContext; +import dev.vality.damsel.fraudbusters.ShopContext; import dev.vality.fraudbusters.constant.ClickhouseUtilsValue; import dev.vality.fraudbusters.fraud.model.PaymentModel; -import org.springframework.util.StringUtils; public class PaymentModelFactory { public static PaymentModel buildPaymentModel(InspectUserContext context, ShopContext shopContext) { PaymentModel paymentModel = new PaymentModel(); - paymentModel.setPartyId(shopContext.getParty().getPartyRef().getId()); - paymentModel.setShopId(shopContext.getShop().getShopRef().getId()); + paymentModel.setPartyId(shopContext.getPartyId()); + paymentModel.setShopId(shopContext.getShopId()); paymentModel.setTimestamp(System.currentTimeMillis()); if (context.getUserInfo() != null) { - paymentModel.setEmail( - context.getUserInfo().isSetEmail() && StringUtils.hasLength(context.getUserInfo().getEmail()) - ? context.getUserInfo().getEmail().toLowerCase() - : ClickhouseUtilsValue.UNKNOWN); - paymentModel.setPhone( - context.getUserInfo().isSetPhoneNumber() - && StringUtils.hasLength(context.getUserInfo().getPhoneNumber()) - ? context.getUserInfo().getPhoneNumber() - : ClickhouseUtilsValue.UNKNOWN + paymentModel.setEmail(context.getUserInfo().getEmail().isPresent() + ? context.getUserInfo().getEmail().get() + : ClickhouseUtilsValue.UNKNOWN); + paymentModel.setPhone(context.getUserInfo().getPhone().isPresent() + ? context.getUserInfo().getPhone().get() + : ClickhouseUtilsValue.UNKNOWN ); } else { paymentModel.setEmail(ClickhouseUtilsValue.UNKNOWN); From 9ee206377bcaa7fa0e56bee7d57ed679da50454c Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Thu, 29 Jan 2026 20:15:45 +0300 Subject: [PATCH 06/12] Change iface for inspect user --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 21fe39c5..4af24f51 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ UTF-8 1.0.7 0.3.1 - 1.121-c3e5076 + 1.128-79c32f2 1.7-6d29f86 1.44-5dbd6d4 21.12.0 From 17bacef847e246249be0da89a37dfe5dfe39c42a Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Thu, 29 Jan 2026 20:23:54 +0300 Subject: [PATCH 07/12] Change iface for inspect user --- .../converter/WithdrawalToDgraphWithdrawalConverter.java | 1 - .../setter/WithdrawalBatchPreparedStatementSetter.java | 5 ++--- .../dev/vality/fraudbusters/util/PaymentModelFactory.java | 8 ++++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/converter/WithdrawalToDgraphWithdrawalConverter.java b/src/main/java/dev/vality/fraudbusters/converter/WithdrawalToDgraphWithdrawalConverter.java index 371bd27a..947cb450 100644 --- a/src/main/java/dev/vality/fraudbusters/converter/WithdrawalToDgraphWithdrawalConverter.java +++ b/src/main/java/dev/vality/fraudbusters/converter/WithdrawalToDgraphWithdrawalConverter.java @@ -35,7 +35,6 @@ public DgraphWithdrawal convert(Withdrawal withdrawal) { Account account = withdrawal.getAccount(); if (account != null) { dgraphWithdrawal.setAccountId(account.getId()); - dgraphWithdrawal.setAccountIdentity(account.getIdentity()); dgraphWithdrawal.setAccountCurrency( account.getCurrency() == null ? null : createDgraphCurrency(account.getCurrency().getSymbolicCode())); diff --git a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/setter/WithdrawalBatchPreparedStatementSetter.java b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/setter/WithdrawalBatchPreparedStatementSetter.java index f2e05445..492f7558 100644 --- a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/setter/WithdrawalBatchPreparedStatementSetter.java +++ b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/setter/WithdrawalBatchPreparedStatementSetter.java @@ -18,11 +18,11 @@ public class WithdrawalBatchPreparedStatementSetter implements BatchPreparedStat public static final String FIELDS = """ timestamp, eventTimeHour, eventTime, id, amount, currency, bin, lastDigits, cardToken, paymentSystem, - terminal, providerId, bankCountry, identityId, accountId, accountCurrency, status, errorCode, + terminal, providerId, bankCountry, accountId, accountCurrency, status, errorCode, errorReason """; - public static final String FIELDS_MARK = "?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?"; + public static final String FIELDS_MARK = "?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?"; private final List batch; @@ -60,7 +60,6 @@ public void setValues(PreparedStatement ps, int i) throws SQLException { : UNKNOWN ); - ps.setString(l++, withdrawal.getAccount().getIdentity()); ps.setString(l++, withdrawal.getAccount().getId()); ps.setString(l++, withdrawal.getAccount().getCurrency().getSymbolicCode()); diff --git a/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java b/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java index 23f799df..661e7a55 100644 --- a/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java +++ b/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java @@ -13,11 +13,11 @@ public static PaymentModel buildPaymentModel(InspectUserContext context, ShopCon paymentModel.setShopId(shopContext.getShopId()); paymentModel.setTimestamp(System.currentTimeMillis()); if (context.getUserInfo() != null) { - paymentModel.setEmail(context.getUserInfo().getEmail().isPresent() - ? context.getUserInfo().getEmail().get() + paymentModel.setEmail(context.getUserInfo().isSetEmail() + ? context.getUserInfo().getEmail() : ClickhouseUtilsValue.UNKNOWN); - paymentModel.setPhone(context.getUserInfo().getPhone().isPresent() - ? context.getUserInfo().getPhone().get() + paymentModel.setPhone(context.getUserInfo().isSetPhone() + ? context.getUserInfo().getPhone() : ClickhouseUtilsValue.UNKNOWN ); } else { From b0ea6aeffc99440acb790dd18779fcce134da819 Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Thu, 29 Jan 2026 20:36:04 +0300 Subject: [PATCH 08/12] Change iface for inspect user --- .../vality/fraudbusters/factory/TestDgraphObjectFactory.java | 3 +-- src/test/java/dev/vality/fraudbusters/util/BeanUtil.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/java/dev/vality/fraudbusters/factory/TestDgraphObjectFactory.java b/src/test/java/dev/vality/fraudbusters/factory/TestDgraphObjectFactory.java index 437b8c3d..cf106d4b 100644 --- a/src/test/java/dev/vality/fraudbusters/factory/TestDgraphObjectFactory.java +++ b/src/test/java/dev/vality/fraudbusters/factory/TestDgraphObjectFactory.java @@ -419,8 +419,7 @@ public static Withdrawal generateWithdrawal(int idx, withdrawal.setAccount( new Account() .setId("AID-1") - .setCurrency(new CurrencyRef().setSymbolicCode("RUB")) - .setIdentity("IDX_P_1")); + .setCurrency(new CurrencyRef().setSymbolicCode("RUB")); withdrawal.setError( new Error() .setErrorCode("CODE-1") diff --git a/src/test/java/dev/vality/fraudbusters/util/BeanUtil.java b/src/test/java/dev/vality/fraudbusters/util/BeanUtil.java index ee2de81d..1c72942d 100644 --- a/src/test/java/dev/vality/fraudbusters/util/BeanUtil.java +++ b/src/test/java/dev/vality/fraudbusters/util/BeanUtil.java @@ -391,8 +391,7 @@ public static TemplateReference createTemplateReference(boolean isGlobal, private static Account createAccount() { return new Account() .setCurrency(createRubCurrency()) - .setId(ACCOUNT_ID) - .setIdentity(IDENTITY_ID); + .setId(ACCOUNT_ID); } @NotNull From 8a792fb4f9fda86906e1d79754935f7d83cd4d9c Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Thu, 29 Jan 2026 20:46:50 +0300 Subject: [PATCH 09/12] Change iface for inspect user --- .../vality/fraudbusters/factory/TestDgraphObjectFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/dev/vality/fraudbusters/factory/TestDgraphObjectFactory.java b/src/test/java/dev/vality/fraudbusters/factory/TestDgraphObjectFactory.java index cf106d4b..1f4bfb59 100644 --- a/src/test/java/dev/vality/fraudbusters/factory/TestDgraphObjectFactory.java +++ b/src/test/java/dev/vality/fraudbusters/factory/TestDgraphObjectFactory.java @@ -1,11 +1,11 @@ package dev.vality.fraudbusters.factory; import dev.vality.damsel.domain.*; +import dev.vality.damsel.fraudbusters.*; import dev.vality.damsel.fraudbusters.ClientInfo; import dev.vality.damsel.fraudbusters.CryptoWallet; import dev.vality.damsel.fraudbusters.DigitalWallet; import dev.vality.damsel.fraudbusters.Error; -import dev.vality.damsel.fraudbusters.*; import dev.vality.fraudbusters.domain.dgraph.common.*; import dev.vality.fraudbusters.domain.dgraph.side.*; import dev.vality.fraudbusters.factory.properties.OperationProperties; @@ -419,7 +419,7 @@ public static Withdrawal generateWithdrawal(int idx, withdrawal.setAccount( new Account() .setId("AID-1") - .setCurrency(new CurrencyRef().setSymbolicCode("RUB")); + .setCurrency(new CurrencyRef().setSymbolicCode("RUB"))); withdrawal.setError( new Error() .setErrorCode("CODE-1") From f70b9980464006af431b5905f7908712e05f03ed Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Thu, 29 Jan 2026 21:54:56 +0300 Subject: [PATCH 10/12] Change iface for inspect user --- .../handler/FraudInspectorHandlerTest.java | 16 ++-- .../payment/handler/InspectorHandlerTest.java | 96 +++++++++++++++++++ 2 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 src/test/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandlerTest.java diff --git a/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java index 354be067..2e885328 100644 --- a/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java +++ b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java @@ -84,6 +84,14 @@ void isExistInBlackList() throws TException { assertEquals(false, existInBlackList); } + private BlackListContext createBlackListContext() { + return new BlackListContext() + .setValue("test") + .setFieldName("field_test") + .setFirstId("test_id") + .setSecondId("test_sec_id"); + } + @Test void inspectUserShopsBlocked() throws TException { FraudInspectorHandler fraudInspectorHandler = new FraudInspectorHandler( @@ -117,14 +125,6 @@ void inspectUserShopsBlocked() throws TException { } } - private BlackListContext createBlackListContext() { - return new BlackListContext() - .setValue("test") - .setFieldName("field_test") - .setFirstId("test_id") - .setSecondId("test_sec_id"); - } - private InspectUserContext createInspectUserContext() { ContactInfo contactInfo = new ContactInfo(); contactInfo.setEmail("User@Email.Com"); diff --git a/src/test/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandlerTest.java b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandlerTest.java new file mode 100644 index 00000000..21841748 --- /dev/null +++ b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandlerTest.java @@ -0,0 +1,96 @@ +package dev.vality.fraudbusters.resource.payment.handler; + +import dev.vality.damsel.fraudbusters.BlockedShops; +import dev.vality.damsel.fraudbusters.ClientInfo; +import dev.vality.damsel.fraudbusters.InspectUserContext; +import dev.vality.damsel.fraudbusters.ShopContext; +import dev.vality.damsel.wb_list.WbListServiceSrv; +import dev.vality.fraudbusters.converter.CheckedResultToRiskScoreConverter; +import dev.vality.fraudbusters.converter.ContextToFraudRequestConverter; +import dev.vality.fraudbusters.domain.CheckedResultModel; +import dev.vality.fraudbusters.domain.ConcreteResultModel; +import dev.vality.fraudbusters.domain.FraudResult; +import dev.vality.fraudbusters.fraud.model.PaymentModel; +import dev.vality.fraudbusters.stream.TemplateVisitor; +import dev.vality.fraudo.constant.ResultStatus; +import org.apache.thrift.TException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith({MockitoExtension.class, SpringExtension.class}) +class InspectorHandlerTest { + + @MockitoBean + CheckedResultToRiskScoreConverter checkedResultToRiskScoreConverter; + @MockitoBean + ContextToFraudRequestConverter requestConverter; + @MockitoBean + TemplateVisitor templateVisitor; + @MockitoBean + KafkaTemplate kafkaFraudResultTemplate; + @MockitoBean + WbListServiceSrv.Iface wbListServiceSrv; + + @Test + void inspectUserShopsBlocked() throws TException { + InspectorHandler fraudInspectorHandler = new InspectorHandler( + templateVisitor + ); + + when(templateVisitor.visit(any())).thenAnswer(invocation -> { + PaymentModel model = invocation.getArgument(0); + if (model != null && "shop_1".equals(model.getShopId())) { + return createCheckedResult(ResultStatus.DECLINE); + } + return createCheckedResult(ResultStatus.THREE_DS); + }); + + BlockedShops blockedShops = fraudInspectorHandler.inspectUserShops(createInspectUserContext()); + + assertEquals(1, blockedShops.getShopListSize()); + assertEquals("shop_1", blockedShops.getShopList().get(0).getShopId()); + + ArgumentCaptor captor = ArgumentCaptor.forClass(PaymentModel.class); + verify(templateVisitor, times(2)).visit(captor.capture()); + for (PaymentModel model : captor.getAllValues()) { + assertEquals("party_1", model.getPartyId()); + assertEquals("user@email.com", model.getEmail()); + assertEquals("79990001122", model.getPhone()); + } + } + + private InspectUserContext createInspectUserContext() { + ClientInfo clientInfo = new ClientInfo(); + clientInfo.setEmail("User@Email.Com"); + clientInfo.setPhone("79990001122"); + return new InspectUserContext() + .setUserInfo(clientInfo) + .setShopList(List.of( + createShopContext("party_1", "shop_1"), + createShopContext("party_1", "shop_2") + )); + } + + private ShopContext createShopContext(String partyId, String shopId) { + return new ShopContext() + .setPartyId(partyId) + .setShopId(shopId); + } + + private CheckedResultModel createCheckedResult(ResultStatus status) { + CheckedResultModel checkedResultModel = new CheckedResultModel(); + checkedResultModel.setResultModel(new ConcreteResultModel(status, null, null)); + return checkedResultModel; + } +} From b4a068541d0bca52732ab019a07ca95b1b0d6cde Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Thu, 29 Jan 2026 22:35:12 +0300 Subject: [PATCH 11/12] Change iface for inspect user --- .../util/PaymentModelFactory.java | 2 +- .../handler/FraudInspectorHandlerTest.java | 81 ------------------- .../payment/handler/InspectorHandlerTest.java | 2 +- 3 files changed, 2 insertions(+), 83 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java b/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java index 661e7a55..c1901b19 100644 --- a/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java +++ b/src/main/java/dev/vality/fraudbusters/util/PaymentModelFactory.java @@ -14,7 +14,7 @@ public static PaymentModel buildPaymentModel(InspectUserContext context, ShopCon paymentModel.setTimestamp(System.currentTimeMillis()); if (context.getUserInfo() != null) { paymentModel.setEmail(context.getUserInfo().isSetEmail() - ? context.getUserInfo().getEmail() + ? context.getUserInfo().getEmail().toLowerCase() : ClickhouseUtilsValue.UNKNOWN); paymentModel.setPhone(context.getUserInfo().isSetPhone() ? context.getUserInfo().getPhone() diff --git a/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java index 2e885328..5081afcb 100644 --- a/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java +++ b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/FraudInspectorHandlerTest.java @@ -1,17 +1,6 @@ package dev.vality.fraudbusters.resource.payment.handler; -import dev.vality.damsel.domain.Category; -import dev.vality.damsel.domain.ContactInfo; -import dev.vality.damsel.domain.PartyConfigRef; -import dev.vality.damsel.domain.ShopConfigRef; import dev.vality.damsel.proxy_inspector.BlackListContext; -import dev.vality.damsel.proxy_inspector.BlockedShops; -import dev.vality.damsel.proxy_inspector.InspectUserContext; -import dev.vality.damsel.proxy_inspector.InspectorProxySrv; -import dev.vality.damsel.proxy_inspector.Party; -import dev.vality.damsel.proxy_inspector.Shop; -import dev.vality.damsel.proxy_inspector.ShopContext; -import dev.vality.damsel.domain.ShopLocation; import dev.vality.damsel.wb_list.ListNotFound; import dev.vality.damsel.wb_list.WbListServiceSrv; import dev.vality.fraudbusters.converter.CheckedResultToRiskScoreConverter; @@ -23,27 +12,15 @@ import dev.vality.fraudbusters.stream.TemplateVisitor; import dev.vality.fraudo.constant.ResultStatus; import org.apache.thrift.TException; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; import org.springframework.kafka.core.KafkaTemplate; -import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.junit.jupiter.SpringExtension; -import java.util.ArrayList; -import java.util.List; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith({MockitoExtension.class, SpringExtension.class}) @@ -92,64 +69,6 @@ private BlackListContext createBlackListContext() { .setSecondId("test_sec_id"); } - @Test - void inspectUserShopsBlocked() throws TException { - FraudInspectorHandler fraudInspectorHandler = new FraudInspectorHandler( - "test", - checkedResultToRiskScoreConverter, - requestConverter, - templateVisitor, - kafkaFraudResultTemplate, - wbListServiceSrv - ); - - when(templateVisitor.visit(any())).thenAnswer(invocation -> { - PaymentModel model = invocation.getArgument(0); - if (model != null && "shop_1".equals(model.getShopId())) { - return createCheckedResult(ResultStatus.DECLINE); - } - return createCheckedResult(ResultStatus.THREE_DS); - }); - - BlockedShops blockedShops = fraudInspectorHandler.inspectUser(createInspectUserContext()); - - assertEquals(1, blockedShops.getShopListSize()); - assertEquals("shop_1", blockedShops.getShopList().get(0).getShop().getShopRef().getId()); - - ArgumentCaptor captor = ArgumentCaptor.forClass(PaymentModel.class); - verify(templateVisitor, times(2)).visit(captor.capture()); - for (PaymentModel model : captor.getAllValues()) { - assertEquals("party_1", model.getPartyId()); - assertEquals("user@email.com", model.getEmail()); - assertEquals("79990001122", model.getPhone()); - } - } - - private InspectUserContext createInspectUserContext() { - ContactInfo contactInfo = new ContactInfo(); - contactInfo.setEmail("User@Email.Com"); - contactInfo.setPhoneNumber("79990001122"); - return new InspectUserContext() - .setUserInfo(contactInfo) - .setShopList(List.of( - createShopContext("party_1", "shop_1"), - createShopContext("party_1", "shop_2") - )); - } - - private ShopContext createShopContext(String partyId, String shopId) { - ShopLocation location = new ShopLocation(); - location.setUrl("http://example.com"); - return new ShopContext() - .setParty(new Party(new PartyConfigRef(partyId))) - .setShop(new Shop( - new ShopConfigRef(shopId), - new Category("category", "category"), - "shop-name", - location - )); - } - private CheckedResultModel createCheckedResult(ResultStatus status) { CheckedResultModel checkedResultModel = new CheckedResultModel(); checkedResultModel.setResultModel(new ConcreteResultModel(status, null, null)); diff --git a/src/test/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandlerTest.java b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandlerTest.java index 21841748..47387948 100644 --- a/src/test/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandlerTest.java +++ b/src/test/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandlerTest.java @@ -72,7 +72,7 @@ void inspectUserShopsBlocked() throws TException { private InspectUserContext createInspectUserContext() { ClientInfo clientInfo = new ClientInfo(); - clientInfo.setEmail("User@Email.Com"); + clientInfo.setEmail("user@email.com"); clientInfo.setPhone("79990001122"); return new InspectUserContext() .setUserInfo(clientInfo) From d4da4d865ffe45115e2c716342423f46834cd30b Mon Sep 17 00:00:00 2001 From: kostyastruga Date: Fri, 30 Jan 2026 11:11:06 +0300 Subject: [PATCH 12/12] Change iface for inspect user --- .../resource/payment/handler/InspectorHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandler.java b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandler.java index 533d03ac..c57c5a45 100644 --- a/src/main/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandler.java +++ b/src/main/java/dev/vality/fraudbusters/resource/payment/handler/InspectorHandler.java @@ -37,7 +37,7 @@ public class InspectorHandler implements InspectorServiceSrv.Iface { ) public BlockedShops inspectUserShops(InspectUserContext context) throws InvalidRequest, TException { if (CollectionUtils.isEmpty(context.getShopList())) { - log.warn("FraudInspectorHandler inspectUser with empty shopList: {}", context); + log.warn("InspectorHandler inspectUser with empty shopList: {}", context); return new BlockedShops().setShopList(Collections.emptyList()); } try { @@ -50,10 +50,10 @@ public BlockedShops inspectUserShops(InspectUserContext context) throws InvalidR .filter(entry -> isDeclineResult(entry.getValue())) .map(AbstractMap.SimpleEntry::getKey) .collect(Collectors.toList()); - log.debug("FraudInspectorHandler inspectUser result blockedShops: {}", blockedShops); + log.debug("InspectorHandler inspectUser result blockedShops: {}", blockedShops); return new BlockedShops().setShopList(blockedShops); } catch (Exception e) { - log.warn("FraudInspectorHandler error when inspectUser e: ", e); + log.warn("InspectorHandler error when inspectUser e: ", e); return new BlockedShops().setShopList(Collections.emptyList()); } }