diff --git a/pom.xml b/pom.xml index cf188b1..cc5e718 100644 --- a/pom.xml +++ b/pom.xml @@ -81,7 +81,7 @@ dev.vality damsel - 1.611-958e5f0 + 1.619-da17a84 dev.vality @@ -127,7 +127,7 @@ dev.vality swag-webhook-events - 1.112-a02ceb6-client + 1.122-9daaca8-client dev.vality diff --git a/src/main/java/dev/vality/hooker/converter/InvoiceChangeToUserInteractionConverter.java b/src/main/java/dev/vality/hooker/converter/InvoiceChangeToUserInteractionConverter.java new file mode 100644 index 0000000..637322f --- /dev/null +++ b/src/main/java/dev/vality/hooker/converter/InvoiceChangeToUserInteractionConverter.java @@ -0,0 +1,56 @@ +package dev.vality.hooker.converter; + +import dev.vality.damsel.payment_processing.InvoiceChange; +import dev.vality.damsel.user_interaction.*; +import dev.vality.hooker.model.interaction.PaymentTerminalReceipt; +import dev.vality.hooker.model.interaction.UserInteraction; +import dev.vality.hooker.model.interaction.*; +import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.Nullable; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class InvoiceChangeToUserInteractionConverter implements Converter { + + @Override + public UserInteraction convert(InvoiceChange source) { + var interaction = source.getInvoicePaymentChange().getPayload().getInvoicePaymentSessionChange().getPayload() + .getSessionInteractionChanged().getInteraction(); + return createUserInteraction(interaction); + } + + @Nullable + private static UserInteraction createUserInteraction( + dev.vality.damsel.user_interaction.UserInteraction interaction) { + UserInteraction userInteraction = null; + if (interaction.isSetApiExtensionRequest()) { + userInteraction = new ApiExtension(interaction.getApiExtensionRequest().getApiType()); + } else if (interaction.isSetCryptoCurrencyTransferRequest()) { + CryptoCurrencyTransferRequest cryptoCurrencyTransferRequest = + interaction.getCryptoCurrencyTransferRequest(); + CryptoCash cryptoCash = cryptoCurrencyTransferRequest.getCryptoCash(); + userInteraction = new CryptoCurrencyTransfer(cryptoCurrencyTransferRequest.getCryptoAddress(), + cryptoCash.getCryptoAmount(), + cryptoCash.getCryptoSymbolicCode()); + } else if (interaction.isSetPaymentTerminalReciept()) { + dev.vality.damsel.user_interaction.PaymentTerminalReceipt paymentTerminalReciept = + interaction.getPaymentTerminalReciept(); + userInteraction = new PaymentTerminalReceipt(paymentTerminalReciept.getShortPaymentId(), + paymentTerminalReciept.getDue()); + } else if (interaction.isSetQrCodeDisplayRequest()) { + QrCode qrCode = interaction.getQrCodeDisplayRequest().getQrCode(); + userInteraction = new QrCodeDisplay(qrCode.getPayload()); + } else if (interaction.isSetRedirect()) { + if (interaction.getRedirect().isSetPostRequest()) { + BrowserPostRequest postRequest = interaction.getRedirect().getPostRequest(); + userInteraction = new BrowserHttpInteraction("post", postRequest.getUri(), postRequest.getForm()); + } else { + BrowserGetRequest getRequest = interaction.getRedirect().getGetRequest(); + userInteraction = new BrowserHttpInteraction("get", getRequest.getUri(), null); + } + } + return userInteraction; + } +} diff --git a/src/main/java/dev/vality/hooker/converter/UserInteractionConverter.java b/src/main/java/dev/vality/hooker/converter/UserInteractionConverter.java new file mode 100644 index 0000000..312bb89 --- /dev/null +++ b/src/main/java/dev/vality/hooker/converter/UserInteractionConverter.java @@ -0,0 +1,98 @@ +package dev.vality.hooker.converter; + +import dev.vality.hooker.model.InvoicingMessage; +import dev.vality.hooker.model.interaction.PaymentTerminalReceipt; +import dev.vality.hooker.model.interaction.*; +import dev.vality.hooker.utils.TimeUtils; +import dev.vality.swag_webhook_events.model.*; +import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.NotNull; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class UserInteractionConverter implements Converter { + + @Override + public UserInteractionDetails convert(InvoicingMessage invoicingMessage) { + UserInteractionDetails userInteractionDetails = new UserInteractionDetails(); + UserInteraction interaction = invoicingMessage.getUserInteraction(); + if (interaction instanceof BrowserHttpInteraction browserHttpInteraction) { + return createBrowserHttpRequest(browserHttpInteraction); + } else if (interaction instanceof ApiExtension apiExtension) { + return createApiExtensionRequest(apiExtension); + } else if (interaction instanceof CryptoCurrencyTransfer cryptoCurrencyTransfer) { + return createCryptoCurrencyTransferRequest(cryptoCurrencyTransfer); + } else if (interaction instanceof PaymentTerminalReceipt paymentTerminalReceipt) { + return createPaymentTerminalReceipt(paymentTerminalReceipt); + } else if (interaction instanceof QrCodeDisplay qrCodeDisplay) { + return createQrCodeDisplayRequest(qrCodeDisplay); + } + return userInteractionDetails; + } + + @NotNull + private static QrCodeDisplayRequest createQrCodeDisplayRequest(QrCodeDisplay qrCodeDisplay) { + QrCodeDisplayRequest qrCodeDisplayRequest = new QrCodeDisplayRequest(); + QrCodeDisplayInfo qrCodeDisplayInfo = new QrCodeDisplayInfo(); + qrCodeDisplayInfo.setQrCode(new String(qrCodeDisplay.getQrCode())); + qrCodeDisplayRequest.setQrCodeDisplayInfo(qrCodeDisplayInfo); + qrCodeDisplayRequest.setUserInteractionType( + UserInteractionDetails.UserInteractionTypeEnum.QRCODEDISPLAYREQUEST); + return qrCodeDisplayRequest; + } + + @NotNull + private static dev.vality.swag_webhook_events.model.PaymentTerminalReceipt createPaymentTerminalReceipt( + PaymentTerminalReceipt paymentTerminalReceipt) { + var paymentTerminalReceiptRequest = new dev.vality.swag_webhook_events.model.PaymentTerminalReceipt(); + PaymentTerminalReceiptInfo paymentTerminalReceiptInfo = new PaymentTerminalReceiptInfo(); + paymentTerminalReceiptInfo.setShortPaymentId(paymentTerminalReceipt.getShortPaymentId()); + paymentTerminalReceiptInfo.setDue(TimeUtils.toOffsetDateTime(paymentTerminalReceipt.getDue())); + paymentTerminalReceiptRequest.setPaymentTerminalReceiptInfo(paymentTerminalReceiptInfo); + paymentTerminalReceiptRequest.setUserInteractionType( + UserInteractionDetails.UserInteractionTypeEnum.PAYMENTTERMINALRECEIPT); + return paymentTerminalReceiptRequest; + } + + @NotNull + private static CryptoCurrencyTransferRequest createCryptoCurrencyTransferRequest( + CryptoCurrencyTransfer cryptoCurrencyTransfer) { + CryptoCurrencyTransferInfo cryptoCurrencyTransferInfo = new CryptoCurrencyTransferInfo(); + cryptoCurrencyTransferInfo.setCryptoAddress(cryptoCurrencyTransfer.getCryptoAddress()); + cryptoCurrencyTransferInfo.setCryptoCurrency(cryptoCurrencyTransfer.getCryptoSymbolicCode()); + Rational cryptoAmount = new Rational(); + cryptoAmount.setDenominator(cryptoCurrencyTransfer.getCryptoAmount().getP()); + cryptoAmount.setDivider(cryptoCurrencyTransfer.getCryptoAmount().getQ()); + cryptoCurrencyTransferInfo.setCryptoAmount(cryptoAmount); + CryptoCurrencyTransferRequest cryptoCurrencyTransferRequest = new CryptoCurrencyTransferRequest(); + cryptoCurrencyTransferRequest.setCryptoCurrencyTransferInfo(cryptoCurrencyTransferInfo); + cryptoCurrencyTransferRequest.setUserInteractionType( + UserInteractionDetails.UserInteractionTypeEnum.CRYPTOCURRENCYTRANSFERREQUEST); + return cryptoCurrencyTransferRequest; + } + + @NotNull + private static ApiExtensionRequest createApiExtensionRequest(ApiExtension apiExtension) { + ApiExtensionRequest apiExtensionRequest = new ApiExtensionRequest(); + ApiExtensionInfo apiExtensionInfo = new ApiExtensionInfo(); + apiExtensionInfo.setApiType(apiExtension.getApiType()); + apiExtensionRequest.setApiExtensionInfo(apiExtensionInfo); + apiExtensionRequest.setUserInteractionType(UserInteractionDetails.UserInteractionTypeEnum.APIEXTENSIONREQUEST); + return apiExtensionRequest; + } + + @NotNull + private static BrowserHTTPRequest createBrowserHttpRequest(BrowserHttpInteraction browserHttpInteraction) { + BrowserHTTPInfo browserHttpInfo = new BrowserHTTPInfo(); + browserHttpInfo.setUrl(browserHttpInteraction.getUrl()); + browserHttpInfo.setRequestType( + BrowserHTTPInfo.RequestTypeEnum.fromValue(browserHttpInteraction.getRequestType())); + browserHttpInfo.setForm(browserHttpInteraction.getForm()); + BrowserHTTPRequest browserHttpRequest = new BrowserHTTPRequest(); + browserHttpRequest.setBrowserHTTPInfo(browserHttpInfo); + browserHttpRequest.setUserInteractionType(UserInteractionDetails.UserInteractionTypeEnum.BROWSERHTTPREQUEST); + return browserHttpRequest; + } +} diff --git a/src/main/java/dev/vality/hooker/handler/invoicing/InvoicePaymentUserInteractionChangeCompletedMapper.java b/src/main/java/dev/vality/hooker/handler/invoicing/InvoicePaymentUserInteractionChangeCompletedMapper.java new file mode 100644 index 0000000..729a0b2 --- /dev/null +++ b/src/main/java/dev/vality/hooker/handler/invoicing/InvoicePaymentUserInteractionChangeCompletedMapper.java @@ -0,0 +1,68 @@ +package dev.vality.hooker.handler.invoicing; + +import dev.vality.damsel.payment_processing.InvoiceChange; +import dev.vality.geck.filter.Filter; +import dev.vality.geck.filter.PathConditionFilter; +import dev.vality.geck.filter.condition.IsNullCondition; +import dev.vality.geck.filter.rule.PathConditionRule; +import dev.vality.hooker.converter.InvoiceChangeToUserInteractionConverter; +import dev.vality.hooker.dao.InvoicingMessageDao; +import dev.vality.hooker.model.EventType; +import dev.vality.hooker.model.InvoicingMessage; +import dev.vality.hooker.model.InvoicingMessageEnum; +import dev.vality.hooker.model.InvoicingMessageKey; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class InvoicePaymentUserInteractionChangeCompletedMapper extends NeedReadInvoiceEventMapper { + + @Autowired + private InvoiceChangeToUserInteractionConverter userInteractionConverter; + + private EventType eventType = EventType.INVOICE_PAYMENT_USER_INTERACTION_CHANGE_COMPLETED; + + private Filter filter = + new PathConditionFilter(new PathConditionRule(eventType.getThriftPath(), new IsNullCondition().not())); + + public InvoicePaymentUserInteractionChangeCompletedMapper(InvoicingMessageDao messageDao) { + super(messageDao); + } + + @Override + public Filter getFilter() { + return filter; + } + + @Override + protected InvoicingMessageKey getMessageKey(String invoiceId, InvoiceChange ic) { + return InvoicingMessageKey.builder() + .invoiceId(invoiceId) + .paymentId(ic.getInvoicePaymentChange().getId()) + .type(InvoicingMessageEnum.PAYMENT) + .build(); + } + + @Override + protected InvoicingMessageEnum getMessageType() { + return InvoicingMessageEnum.PAYMENT; + } + + @Override + protected EventType getEventType() { + return eventType; + } + + @Override + protected void modifyMessage(InvoiceChange ic, InvoicingMessage message) { + message.setUserInteraction(userInteractionConverter.convert(ic)); + } + + @Override + public boolean accept(InvoiceChange change) { + return getFilter().match(change) + && !change.getInvoicePaymentChange().getPayload().getInvoicePaymentSessionChange().getPayload() + .getSessionInteractionChanged() + .getStatus().isSetCompleted(); + } +} \ No newline at end of file diff --git a/src/main/java/dev/vality/hooker/handler/invoicing/InvoicePaymentUserInteractionChangeRequestedMapper.java b/src/main/java/dev/vality/hooker/handler/invoicing/InvoicePaymentUserInteractionChangeRequestedMapper.java new file mode 100644 index 0000000..b71d8c2 --- /dev/null +++ b/src/main/java/dev/vality/hooker/handler/invoicing/InvoicePaymentUserInteractionChangeRequestedMapper.java @@ -0,0 +1,63 @@ +package dev.vality.hooker.handler.invoicing; + +import dev.vality.damsel.payment_processing.InvoiceChange; +import dev.vality.geck.filter.Filter; +import dev.vality.geck.filter.PathConditionFilter; +import dev.vality.geck.filter.condition.IsNullCondition; +import dev.vality.geck.filter.rule.PathConditionRule; +import dev.vality.hooker.dao.InvoicingMessageDao; +import dev.vality.hooker.model.*; +import org.springframework.stereotype.Component; + +@Component +public class InvoicePaymentUserInteractionChangeRequestedMapper extends NeedReadInvoiceEventMapper { + + private EventType eventType = EventType.INVOICE_PAYMENT_USER_INTERACTION_CHANGE_REQUESTED; + + private Filter filter = + new PathConditionFilter(new PathConditionRule(eventType.getThriftPath(), new IsNullCondition().not())); + + public InvoicePaymentUserInteractionChangeRequestedMapper(InvoicingMessageDao messageDao) { + super(messageDao); + } + + @Override + public Filter getFilter() { + return filter; + } + + @Override + protected InvoicingMessageKey getMessageKey(String invoiceId, InvoiceChange ic) { + return InvoicingMessageKey.builder() + .invoiceId(invoiceId) + .paymentId(ic.getInvoicePaymentChange().getId()) + .type(InvoicingMessageEnum.PAYMENT) + .build(); + } + + @Override + protected InvoicingMessageEnum getMessageType() { + return InvoicingMessageEnum.PAYMENT; + } + + @Override + protected EventType getEventType() { + return eventType; + } + + @Override + protected void modifyMessage(InvoiceChange ic, InvoicingMessage message) { + message.setPaymentStatus(PaymentStatusEnum.lookup(ic.getInvoicePaymentChange().getPayload() + .getInvoicePaymentStatusChanged().getStatus().getSetField().getFieldName())); + } + + @Override + public boolean accept(InvoiceChange change) { + return getFilter().match(change) + && !change.getInvoicePaymentChange().getPayload().getInvoicePaymentSessionChange() + .getPayload() + .getSessionInteractionChanged() + .getStatus() + .isSetRequested(); + } +} \ No newline at end of file diff --git a/src/main/java/dev/vality/hooker/model/EventType.java b/src/main/java/dev/vality/hooker/model/EventType.java index c1e4041..985390e 100644 --- a/src/main/java/dev/vality/hooker/model/EventType.java +++ b/src/main/java/dev/vality/hooker/model/EventType.java @@ -18,6 +18,9 @@ public enum EventType { INVOICE_PAYMENT_CASH_FLOW_CHANGED("invoice_payment_change.payload.invoice_payment_cash_flow_changed"), INVOICE_PAYMENT_CASH_CHANGED("invoice_payment_change.payload.invoice_payment_cash_changed"), + INVOICE_PAYMENT_USER_INTERACTION_CHANGE_REQUESTED("invoice_payment_change.payload.user_interaction.status.requested"), + INVOICE_PAYMENT_USER_INTERACTION_CHANGE_COMPLETED("invoice_payment_change.payload.user_interaction.status.completed"), + CUSTOMER_CREATED("customer_created"), CUSTOMER_DELETED("customer_deleted"), CUSTOMER_READY("customer_status_changed.status.ready"), diff --git a/src/main/java/dev/vality/hooker/model/InvoicingMessage.java b/src/main/java/dev/vality/hooker/model/InvoicingMessage.java index e277e7e..3fa1989 100644 --- a/src/main/java/dev/vality/hooker/model/InvoicingMessage.java +++ b/src/main/java/dev/vality/hooker/model/InvoicingMessage.java @@ -1,5 +1,6 @@ package dev.vality.hooker.model; +import dev.vality.hooker.model.interaction.UserInteraction; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; @@ -16,6 +17,7 @@ public class InvoicingMessage extends Message { private PaymentStatusEnum paymentStatus; private String refundId; private RefundStatusEnum refundStatus; + private UserInteraction userInteraction; public boolean isInvoice() { return type == InvoicingMessageEnum.INVOICE; diff --git a/src/main/java/dev/vality/hooker/model/interaction/ApiExtension.java b/src/main/java/dev/vality/hooker/model/interaction/ApiExtension.java new file mode 100644 index 0000000..7c6b07d --- /dev/null +++ b/src/main/java/dev/vality/hooker/model/interaction/ApiExtension.java @@ -0,0 +1,12 @@ +package dev.vality.hooker.model.interaction; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class ApiExtension implements UserInteraction { + + private String apiType; + +} diff --git a/src/main/java/dev/vality/hooker/model/interaction/BrowserHttpInteraction.java b/src/main/java/dev/vality/hooker/model/interaction/BrowserHttpInteraction.java new file mode 100644 index 0000000..280ed74 --- /dev/null +++ b/src/main/java/dev/vality/hooker/model/interaction/BrowserHttpInteraction.java @@ -0,0 +1,16 @@ +package dev.vality.hooker.model.interaction; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.Map; + +@Data +@AllArgsConstructor +public class BrowserHttpInteraction implements UserInteraction { + + private String requestType; + private String url; + private Map form; + +} diff --git a/src/main/java/dev/vality/hooker/model/interaction/CryptoCurrencyTransfer.java b/src/main/java/dev/vality/hooker/model/interaction/CryptoCurrencyTransfer.java new file mode 100644 index 0000000..464a5fb --- /dev/null +++ b/src/main/java/dev/vality/hooker/model/interaction/CryptoCurrencyTransfer.java @@ -0,0 +1,15 @@ +package dev.vality.hooker.model.interaction; + +import dev.vality.damsel.base.Rational; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class CryptoCurrencyTransfer implements UserInteraction { + + private String cryptoAddress; + public Rational cryptoAmount; + public String cryptoSymbolicCode; + +} diff --git a/src/main/java/dev/vality/hooker/model/interaction/PaymentTerminalReceipt.java b/src/main/java/dev/vality/hooker/model/interaction/PaymentTerminalReceipt.java new file mode 100644 index 0000000..85508e5 --- /dev/null +++ b/src/main/java/dev/vality/hooker/model/interaction/PaymentTerminalReceipt.java @@ -0,0 +1,13 @@ +package dev.vality.hooker.model.interaction; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class PaymentTerminalReceipt implements UserInteraction { + + private String shortPaymentId; + private String due; + +} diff --git a/src/main/java/dev/vality/hooker/model/interaction/QrCodeDisplay.java b/src/main/java/dev/vality/hooker/model/interaction/QrCodeDisplay.java new file mode 100644 index 0000000..f38e89d --- /dev/null +++ b/src/main/java/dev/vality/hooker/model/interaction/QrCodeDisplay.java @@ -0,0 +1,12 @@ +package dev.vality.hooker.model.interaction; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class QrCodeDisplay implements UserInteraction { + + private byte[] qrCode; + +} diff --git a/src/main/java/dev/vality/hooker/model/interaction/UserInteraction.java b/src/main/java/dev/vality/hooker/model/interaction/UserInteraction.java new file mode 100644 index 0000000..e3df607 --- /dev/null +++ b/src/main/java/dev/vality/hooker/model/interaction/UserInteraction.java @@ -0,0 +1,4 @@ +package dev.vality.hooker.model.interaction; + +public interface UserInteraction { +} diff --git a/src/main/java/dev/vality/hooker/service/InvoicingEventService.java b/src/main/java/dev/vality/hooker/service/InvoicingEventService.java index 292ad92..dcc8788 100644 --- a/src/main/java/dev/vality/hooker/service/InvoicingEventService.java +++ b/src/main/java/dev/vality/hooker/service/InvoicingEventService.java @@ -7,6 +7,7 @@ import dev.vality.damsel.payment_processing.InvoicingSrv; import dev.vality.hooker.converter.InvoiceConverter; import dev.vality.hooker.converter.PaymentConverter; import dev.vality.hooker.converter.RefundConverter; +import dev.vality.hooker.converter.UserInteractionConverter; import dev.vality.hooker.exception.NotFoundException; import dev.vality.hooker.exception.RemoteHostException; import dev.vality.hooker.model.ExpandedPayment; @@ -26,6 +27,7 @@ public class InvoicingEventService private final InvoiceConverter invoiceConverter; private final PaymentConverter paymentConverter; private final RefundConverter refundConverter; + private final UserInteractionConverter userInteractionConverter; @Override public Event getEventByMessage(InvoicingMessage message) { @@ -73,6 +75,10 @@ public class InvoicingEventService .eventType(Event.EventTypeEnum.REFUNDCREATED); case INVOICE_PAYMENT_REFUND_STATUS_CHANGED -> resolveRefundStatusChanged(m, invoiceInfo); case INVOICE_PAYMENT_CASH_CHANGED -> resolvePaymentCashChange(m, invoiceInfo); + case INVOICE_PAYMENT_USER_INTERACTION_CHANGE_REQUESTED -> resolvePaymentUserInteraction(m) + .eventType(Event.EventTypeEnum.PAYMENTINTERACTIONREQUESTED); + case INVOICE_PAYMENT_USER_INTERACTION_CHANGE_COMPLETED -> resolvePaymentUserInteraction(m) + .eventType(Event.EventTypeEnum.PAYMENTINTERACTIONCOMPLETED); default -> throw new UnsupportedOperationException("Unknown event type " + m.getEventType()); }; } @@ -207,7 +213,7 @@ public class InvoicingEventService } private Event resolvePaymentCashChange(InvoicingMessage message, - dev.vality.damsel.payment_processing.Invoice invoiceInfo) { + dev.vality.damsel.payment_processing.Invoice invoiceInfo) { Invoice swagInvoice = getSwagInvoice(invoiceInfo); ExpandedPayment swagPayment = getSwagPayment(message, invoiceInfo); return new PaymentCashChanged() @@ -215,4 +221,9 @@ public class InvoicingEventService .payment(swagPayment) .eventType(Event.EventTypeEnum.PAYMENTCASHCHANGED); } + + private Event resolvePaymentUserInteraction(InvoicingMessage message) { + return new PaymentInteractionRequested() + .userInteractionDetails(userInteractionConverter.convert(message)); + } } diff --git a/src/main/java/dev/vality/hooker/utils/EventFilterUtils.java b/src/main/java/dev/vality/hooker/utils/EventFilterUtils.java index 88445ce..8efec69 100644 --- a/src/main/java/dev/vality/hooker/utils/EventFilterUtils.java +++ b/src/main/java/dev/vality/hooker/utils/EventFilterUtils.java @@ -1,5 +1,6 @@ package dev.vality.hooker.utils; +import dev.vality.damsel.user_interaction.UserInteraction; import dev.vality.damsel.webhooker.*; import dev.vality.hooker.dao.WebhookAdditionalFilter; import dev.vality.hooker.model.EventType; @@ -204,6 +205,14 @@ public class EventFilterUtils { .getFieldName()); } } + } else if (payment.isSetUserInteraction()) { + if (payment.getUserInteraction().getStatus().isSetRequested()) { + webhookAdditionalFilter.setEventType( + EventType.INVOICE_PAYMENT_USER_INTERACTION_CHANGE_REQUESTED); + } else if (payment.getUserInteraction().getStatus().isSetCompleted()) { + webhookAdditionalFilter.setEventType( + EventType.INVOICE_PAYMENT_USER_INTERACTION_CHANGE_COMPLETED); + } } } } diff --git a/src/test/java/dev/vality/hooker/model/InvoicingMessageTest.java b/src/test/java/dev/vality/hooker/model/InvoicingMessageTest.java index 0c5e491..ee8beb2 100644 --- a/src/test/java/dev/vality/hooker/model/InvoicingMessageTest.java +++ b/src/test/java/dev/vality/hooker/model/InvoicingMessageTest.java @@ -9,7 +9,7 @@ public class InvoicingMessageTest { @Test public void testCopy() { - InvoicingMessage invoicingMessage = random(InvoicingMessage.class); + InvoicingMessage invoicingMessage = random(InvoicingMessage.class, "userInteraction"); InvoicingMessage copy = invoicingMessage.copy(); invoicingMessage.setRefundId("asd"); assertNotEquals("asd", copy.getRefundId()); diff --git a/src/test/java/dev/vality/hooker/service/InvoicingEventServiceTest.java b/src/test/java/dev/vality/hooker/service/InvoicingEventServiceTest.java index a59303b..2a123c5 100644 --- a/src/test/java/dev/vality/hooker/service/InvoicingEventServiceTest.java +++ b/src/test/java/dev/vality/hooker/service/InvoicingEventServiceTest.java @@ -2,6 +2,7 @@ package dev.vality.hooker.service; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import dev.vality.damsel.base.Rational; import dev.vality.damsel.domain.InvoicePaid; import dev.vality.damsel.domain.InvoicePaymentPending; import dev.vality.damsel.domain.InvoicePaymentStatus; @@ -9,11 +10,14 @@ import dev.vality.damsel.domain.InvoiceStatus; import dev.vality.damsel.payment_processing.InvoicingSrv; import dev.vality.hooker.config.PostgresqlSpringBootITest; import dev.vality.hooker.model.*; +import dev.vality.hooker.model.interaction.*; import dev.vality.hooker.utils.BuildUtils; import dev.vality.swag_webhook_events.model.Event; import dev.vality.swag_webhook_events.model.RefundSucceeded; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; @@ -45,7 +49,7 @@ public class InvoicingEventServiceTest { @RepeatedTest(7) public void testRefundSucceeded() { - InvoicingMessage message = random(InvoicingMessage.class); + InvoicingMessage message = random(InvoicingMessage.class, "userInteraction"); message.setPaymentId("1"); message.setRefundId("1"); message.setType(InvoicingMessageEnum.REFUND); @@ -64,7 +68,7 @@ public class InvoicingEventServiceTest { @RepeatedTest(7) public void testJson() throws JsonProcessingException { - InvoicingMessage message = random(InvoicingMessage.class); + InvoicingMessage message = random(InvoicingMessage.class, "userInteraction"); message.setPaymentId("1"); message.setType(InvoicingMessageEnum.PAYMENT); message.setEventTime("2016-03-22T06:12:27Z"); @@ -77,4 +81,74 @@ public class InvoicingEventServiceTest { assertTrue(json.contains("\"externalId\":\"payment-external-id\"")); assertTrue(json.contains("\"externalId\":\"invoice-external-id\"")); } + + @Test + public void testUserInteractions() throws JsonProcessingException { + InvoicingMessage message = createDefaultInvoicingMessage(); + message.setEventType(EventType.INVOICE_PAYMENT_USER_INTERACTION_CHANGE_REQUESTED); + message.setUserInteraction(new BrowserHttpInteraction("get", "http://test", null)); + Event event = service.getEventByMessage(message); + String json = objectMapper.writeValueAsString(event); + assertTrue(json.contains("\"eventType\":\"PaymentInteractionRequested\"")); + assertTrue(json.contains("\"requestType\":\"get\"")); + assertTrue(json.contains("\"userInteractionType\":\"BrowserHTTPRequest\"")); + } + + @Test + public void testUserInteractionsCompleted() throws JsonProcessingException { + InvoicingMessage message = createDefaultInvoicingMessage(); + message.setEventType(EventType.INVOICE_PAYMENT_USER_INTERACTION_CHANGE_COMPLETED); + message.setUserInteraction(new QrCodeDisplay("wefvqewvrq32fveqrw".getBytes())); + Event event = service.getEventByMessage(message); + String json = objectMapper.writeValueAsString(event); + assertTrue(json.contains("\"eventType\":\"PaymentInteractionCompleted\"")); + assertTrue(json.contains("\"userInteractionType\":\"QrCodeDisplayRequest\"")); + } + + @Test + public void testUserInteractionsCompletedApiExtension() throws JsonProcessingException { + InvoicingMessage message = createDefaultInvoicingMessage(); + message.setEventType(EventType.INVOICE_PAYMENT_USER_INTERACTION_CHANGE_COMPLETED); + message.setUserInteraction(new ApiExtension("p2p")); + Event event = service.getEventByMessage(message); + String json = objectMapper.writeValueAsString(event); + assertTrue(json.contains("\"eventType\":\"PaymentInteractionCompleted\"")); + assertTrue(json.contains("\"userInteractionType\":\"ApiExtensionRequest\"")); + } + + @Test + public void testUserInteractionsCompletedPaymentTerminal() throws JsonProcessingException { + InvoicingMessage message = createDefaultInvoicingMessage(); + message.setEventType(EventType.INVOICE_PAYMENT_USER_INTERACTION_CHANGE_COMPLETED); + message.setUserInteraction(new PaymentTerminalReceipt("p2p", "2016-03-22T06:12:27Z")); + Event event = service.getEventByMessage(message); + String json = objectMapper.writeValueAsString(event); + assertTrue(json.contains("\"eventType\":\"PaymentInteractionCompleted\"")); + assertTrue(json.contains("\"userInteractionType\":\"PaymentTerminalReceipt\"")); + } + + @Test + public void testUserInteractionsCompletedCrypto() throws JsonProcessingException { + InvoicingMessage message = createDefaultInvoicingMessage(); + message.setEventType(EventType.INVOICE_PAYMENT_USER_INTERACTION_CHANGE_COMPLETED); + message.setUserInteraction(new CryptoCurrencyTransfer("address", new Rational(1L, 10L), "bitcoin")); + Event event = service.getEventByMessage(message); + String json = objectMapper.writeValueAsString(event); + assertTrue(json.contains("\"eventType\":\"PaymentInteractionCompleted\"")); + assertTrue(json.contains("\"userInteractionType\":\"CryptoCurrencyTransferRequest\"")); + assertTrue(json.contains("\"cryptoAddress\":\"address\"")); + assertTrue(json.contains("\"cryptoCurrency\":\"bitcoin\"")); + assertTrue(json.contains("\"denominator\":1")); + } + + @NotNull + private static InvoicingMessage createDefaultInvoicingMessage() { + InvoicingMessage message = new InvoicingMessage(); + message.setId(123L); + message.setPaymentId("271771960"); + message.setSequenceId(123L); + message.setType(InvoicingMessageEnum.PAYMENT); + message.setEventTime("2016-03-22T06:12:27Z"); + return message; + } }