Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
<dependency>
<groupId>dev.vality</groupId>
<artifactId>disputes-proto</artifactId>
<version>1.56-97eaea8</version>
<version>1.58-419fe9c</version>
</dependency>
<dependency>
<groupId>dev.vality</groupId>
Expand All @@ -60,7 +60,7 @@
<dependency>
<groupId>dev.vality</groupId>
<artifactId>damsel</artifactId>
<version>1.679-b5c1dc4</version>
<version>1.696-b07c077</version>
</dependency>
<dependency>
<groupId>dev.vality</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public class ErrorMessage {
public static final String NO_ATTACHMENTS = "no attachments";
public static final String INVOICE_NOT_FOUND = "invoice not found";
public static final String PAYMENT_NOT_FOUND = "payment not found";
public static final String PAYMENT_STATUS_NOT_SUCCESS = "payment status is not success";
public static final String PAYMENT_STATUS_RESTRICTIONS = "payment status restrictions";
public static final String PROVIDER_RESULT_UNEXPECTED = "provider result unexpected";
public static final String DEFAULT_DESTINATION = "dispute via disputes-tg-bot";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.vality.disputes.provider.payments.converter;

import dev.vality.damsel.domain.InvoicePaymentAdjustmentTransactionInfo;
import dev.vality.damsel.payment_processing.InvoicePaymentAdjustmentParams;
import dev.vality.damsel.payment_processing.InvoicePaymentAdjustmentScenario;
import dev.vality.disputes.domain.tables.pojos.ProviderCallback;
import dev.vality.disputes.provider.payments.service.ProviderPaymentsAdjustmentExtractor;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class ProviderPaymentsToInvoicePaymentTransactionInfoAdjustmentParamsConverter {

private final ProviderPaymentsAdjustmentExtractor providerPaymentsAdjustmentExtractor;
private final TransactionInfoThriftConverter transactionInfoThriftConverter;

public InvoicePaymentAdjustmentParams convert(ProviderCallback providerCallback) {
var transactionInfo = transactionInfoThriftConverter.deserialize(providerCallback.getTransactionInfo());
return new InvoicePaymentAdjustmentParams()
.setReason(providerPaymentsAdjustmentExtractor.getReason(providerCallback))
.setScenario(InvoicePaymentAdjustmentScenario.transaction_info(
new InvoicePaymentAdjustmentTransactionInfo(transactionInfo)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package dev.vality.disputes.provider.payments.converter;

import dev.vality.damsel.domain.TransactionInfo;
import lombok.SneakyThrows;
import org.apache.thrift.TDeserializer;
import org.apache.thrift.TSerializer;
import org.springframework.stereotype.Component;

@Component
public class TransactionInfoThriftConverter {

@SneakyThrows
public byte[] serialize(TransactionInfo transactionInfo) {
return new TSerializer().serialize(transactionInfo);
}

@SneakyThrows
public TransactionInfo deserialize(byte[] transactionInfo) {
var result = new TransactionInfo();
new TDeserializer().deserialize(result, transactionInfo);
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ public boolean isCapturedAdjustmentByProviderPaymentsExist(InvoicePayment invoic
providerCallback));
}

public boolean isTransactionInfoAdjustmentByProviderPaymentsExist(InvoicePayment invoicePayment,
ProviderCallback providerCallback) {
return getInvoicePaymentAdjustmentStream(invoicePayment)
.filter(adj -> isProviderPaymentsAdjustment(adj.getReason(), providerCallback))
.anyMatch(adj -> adj.getState() != null && adj.getState().isSetTransactionInfo());
}

private Stream<InvoicePaymentAdjustment> getInvoicePaymentAdjustmentStream(InvoicePayment invoicePayment) {
return Optional.ofNullable(invoicePayment.getAdjustments())
.orElse(List.of())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
import dev.vality.disputes.provider.payments.client.ProviderPaymentsRemoteClient;
import dev.vality.disputes.provider.payments.converter.ProviderPaymentsToInvoicePaymentCapturedAdjustmentParamsConverter;
import dev.vality.disputes.provider.payments.converter.ProviderPaymentsToInvoicePaymentCashFlowAdjustmentParamsConverter;
import dev.vality.disputes.provider.payments.converter.ProviderPaymentsToInvoicePaymentTransactionInfoAdjustmentParamsConverter;
import dev.vality.disputes.provider.payments.converter.TransactionContextConverter;
import dev.vality.disputes.provider.payments.converter.TransactionInfoThriftConverter;
import dev.vality.disputes.provider.payments.dao.ProviderCallbackDao;
import dev.vality.disputes.provider.payments.exception.ProviderCallbackAlreadyExistException;
import dev.vality.disputes.provider.payments.exception.ProviderCallbackStatusWasUpdatedByAnotherThreadException;
Expand All @@ -25,7 +27,6 @@
import dev.vality.disputes.service.external.InvoicingService;
import dev.vality.disputes.util.ChangedAmountResolver;
import dev.vality.disputes.util.PaymentStatusValidator;
import dev.vality.provider.payments.PaymentStatusResult;
import dev.vality.provider.payments.ProviderPaymentsCallbackParams;
import dev.vality.provider.payments.TransactionContext;
import lombok.RequiredArgsConstructor;
Expand All @@ -39,8 +40,7 @@
import java.util.Map;
import java.util.Optional;

import static dev.vality.disputes.constant.ErrorMessage.INVOICE_NOT_FOUND;
import static dev.vality.disputes.constant.ErrorMessage.PAYMENT_NOT_FOUND;
import static dev.vality.disputes.constant.ErrorMessage.*;
import static dev.vality.disputes.util.OptionsExtractor.extractProviderPaymentsCheckStatusDelaySec;
import static dev.vality.disputes.util.ThreadFormatter.buildThreadName;

Expand All @@ -56,6 +56,9 @@ public class ProviderPaymentsService {
providerPaymentsToInvoicePaymentCapturedAdjustmentParamsConverter;
private final ProviderPaymentsToInvoicePaymentCashFlowAdjustmentParamsConverter
providerPaymentsToInvoicePaymentCashFlowAdjustmentParamsConverter;
private final ProviderPaymentsToInvoicePaymentTransactionInfoAdjustmentParamsConverter
providerPaymentsToInvoicePaymentTransactionInfoAdjustmentParamsConverter;
private final TransactionInfoThriftConverter transactionInfoThriftConverter;
private final DisputeCurrencyConverter disputeCurrencyConverter;
private final ProviderPaymentsAdjustmentExtractor providerPaymentsAdjustmentExtractor;
private final ProviderDataService providerDataService;
Expand Down Expand Up @@ -145,15 +148,22 @@ public void checkPaymentStatusAndCreateAdjustment(TransactionContext transaction
checkProviderCallbackExist(transactionContext.getInvoiceId(), transactionContext.getPaymentId());
var paymentStatusResult =
providerPaymentsRemoteClient.checkPaymentStatus(transactionContext, currency, providerData);
var providerCallback = new ProviderCallback();
providerCallback.setInvoiceId(transactionContext.getInvoiceId());
providerCallback.setPaymentId(transactionContext.getPaymentId());
providerCallback.setAmount(amount);
providerCallback.setPaymentStatusSuccess(paymentStatusResult.isSuccess());
paymentStatusResult.getChangedTransactionInfo()
.map(transactionInfoThriftConverter::serialize)
.ifPresent(providerCallback::setTransactionInfo);
if (paymentStatusResult.isSuccess()) {
var providerCallback = new ProviderCallback();
providerCallback.setInvoiceId(transactionContext.getInvoiceId());
providerCallback.setPaymentId(transactionContext.getPaymentId());
providerCallback.setChangedAmount(
ChangedAmountResolver.fromPaymentStatusResult(amount, paymentStatusResult));
providerCallback.setAmount(amount);
log.info("Save providerCallback {}", providerCallback);
providerCallbackDao.save(providerCallback);
} else if (providerCallback.getTransactionInfo() != null) {
log.info("Save unsuccessful providerCallback with transactionInfo {}", providerCallback);
providerCallbackDao.save(providerCallback);
} else {
throw new ProviderPaymentsUnexpectedPaymentStatus(
"providerPaymentsService.checkPaymentStatusAndSave unsuccessful: Cant do createAdjustment");
Expand Down Expand Up @@ -183,10 +193,17 @@ public void callHgForCreateAdjustment(ProviderCallback providerCallback) {
updateNextCheckAfter(providerCallback);
return;
}
if (createTransactionInfoAdjustment(providerCallback, invoicePayment)) {
return;
}
if (statusAction == PaymentStatusValidator.StatusAction.FAILED) {
Comment thread
karle0wne marked this conversation as resolved.
finishFailed(providerCallback, PaymentStatusValidator.getTechnicalErrorMessage(invoicePayment));
return;
}
if (!providerCallback.getPaymentStatusSuccess()) {
finishFailed(providerCallback, PAYMENT_STATUS_NOT_SUCCESS);
return;
}
if (statusAction == PaymentStatusValidator.StatusAction.CAPTURED) {
var changedAmount = ChangedAmountResolver.fromInvoicePayment(invoicePayment.getPayment());
if (changedAmount != null) {
Expand Down Expand Up @@ -281,6 +298,22 @@ private boolean createCashFlowAdjustment(ProviderCallback providerCallback, Invo
}
}

private boolean createTransactionInfoAdjustment(ProviderCallback providerCallback, InvoicePayment invoicePayment) {
if (providerCallback.getTransactionInfo() == null) {
return false;
}
if (!providerPaymentsAdjustmentExtractor.isTransactionInfoAdjustmentByProviderPaymentsExist(
invoicePayment, providerCallback)) {
var transactionInfoParams =
providerPaymentsToInvoicePaymentTransactionInfoAdjustmentParamsConverter.convert(providerCallback);
invoicingService.createPaymentAdjustment(providerCallback.getInvoiceId(), providerCallback.getPaymentId(),
transactionInfoParams);
return true;
}
log.info("Creating TransactionInfoAdjustment was skipped {}", providerCallback);
return false;
}

private void createCapturedAdjustment(ProviderCallback providerCallback, InvoicePayment invoicePayment) {
if (!providerPaymentsAdjustmentExtractor.isCapturedAdjustmentByProviderPaymentsExist(invoicePayment,
providerCallback)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ALTER TABLE dspt.provider_callback
ADD COLUMN "transaction_info" BYTEA,
ADD COLUMN "payment_status_success" BOOLEAN NOT NULL DEFAULT TRUE;
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,29 @@
import dev.vality.damsel.domain.InvoicePaymentProcessed;
import dev.vality.damsel.domain.InvoicePaymentRefunded;
import dev.vality.damsel.domain.InvoicePaymentStatus;
import dev.vality.damsel.domain.TransactionInfo;
import dev.vality.damsel.payment_processing.InvoicePaymentAdjustmentParams;
import dev.vality.disputes.config.AbstractMockitoConfig;
import dev.vality.disputes.config.WireMockSpringBootITest;
import dev.vality.disputes.domain.enums.DisputeStatus;
import dev.vality.disputes.domain.enums.ProviderPaymentsStatus;
import dev.vality.provider.payments.PaymentStatusResult;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.test.context.TestPropertySource;

import java.util.List;
import java.util.Map;

import static dev.vality.disputes.util.MockUtil.createInvoicePayment;
import static dev.vality.disputes.util.MockUtil.getTransactionInfoInvoicePaymentAdjustment;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -124,4 +134,61 @@ public void testSuccessWhenInvoicePaymentStatusIsCapturedWithChangedAmount() {
assertEquals(DisputeStatus.succeeded, disputeDao.get(disputeId).getStatus());
verify(invoicingClient, never()).createPaymentAdjustment(any(), any(), any());
}

@Test
@SneakyThrows
public void testCreateTransactionInfoAdjustment() {
var transactionInfo = new TransactionInfo("new-trx-id", Map.of("rrn", "123"));
var disputeId = pendingFlowHandler.handlePending(
new PaymentStatusResult(true).setChangedTransactionInfo(transactionInfo));
var dispute = disputeDao.get(disputeId);
var providerCallback = providerCallbackDao.get(dispute.getInvoiceId(), dispute.getPaymentId());
assertNotNull(providerCallback.getTransactionInfo());
var invoicePayment = createInvoicePayment(providerCallback.getPaymentId());
when(invoicingClient.getPayment(any(), any())).thenReturn(invoicePayment);

providerPaymentsService.callHgForCreateAdjustment(providerCallback);

var reason = providerPaymentsAdjustmentExtractor.getReason(providerCallback);
invoicePayment.setAdjustments(List.of(
getTransactionInfoInvoicePaymentAdjustment("transaction-info-adjustment", reason, transactionInfo)));
providerPaymentsService.callHgForCreateAdjustment(providerCallback);

var paramsCaptor = ArgumentCaptor.forClass(InvoicePaymentAdjustmentParams.class);
verify(invoicingClient, times(2)).createPaymentAdjustment(any(), any(), paramsCaptor.capture());
var scenarios = paramsCaptor.getAllValues().stream()
.map(InvoicePaymentAdjustmentParams::getScenario)
.toList();
assertTrue(scenarios.get(0).isSetTransactionInfo());
assertEquals(transactionInfo, scenarios.get(0).getTransactionInfo().getTrx());
assertTrue(scenarios.get(1).isSetStatusChange());
assertEquals(ProviderPaymentsStatus.succeeded,
providerCallbackDao.get(dispute.getInvoiceId(), dispute.getPaymentId()).getStatus());
}

@Test
@SneakyThrows
public void testCreateTransactionInfoAdjustmentForUnsuccessfulPaymentStatus() {
var transactionInfo = new TransactionInfo("new-trx-id", Map.of("rrn", "123"));
var disputeId = pendingFlowHandler.handlePending(
new PaymentStatusResult(false).setChangedTransactionInfo(transactionInfo));
var dispute = disputeDao.get(disputeId);
var providerCallback = providerCallbackDao.get(dispute.getInvoiceId(), dispute.getPaymentId());
assertNotNull(providerCallback.getTransactionInfo());
var invoicePayment = createInvoicePayment(providerCallback.getPaymentId());
when(invoicingClient.getPayment(any(), any())).thenReturn(invoicePayment);

providerPaymentsService.callHgForCreateAdjustment(providerCallback);

var reason = providerPaymentsAdjustmentExtractor.getReason(providerCallback);
invoicePayment.setAdjustments(List.of(
getTransactionInfoInvoicePaymentAdjustment("transaction-info-adjustment", reason, transactionInfo)));
providerPaymentsService.callHgForCreateAdjustment(providerCallback);

var paramsCaptor = ArgumentCaptor.forClass(InvoicePaymentAdjustmentParams.class);
verify(invoicingClient).createPaymentAdjustment(any(), any(), paramsCaptor.capture());
assertTrue(paramsCaptor.getValue().getScenario().isSetTransactionInfo());
assertEquals(ProviderPaymentsStatus.failed,
providerCallbackDao.get(dispute.getInvoiceId(), dispute.getPaymentId()).getStatus());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,17 @@ public class PendingFlowHandler {

@SneakyThrows
public UUID handlePending() {
return handlePending(new PaymentStatusResult(true));
}

@SneakyThrows
public UUID handlePending(PaymentStatusResult paymentStatusResult) {
var disputeId = createdFlowHandler.handleCreate();
var providerMock = mock(ProviderDisputesServiceSrv.Client.class);
when(providerMock.checkDisputeStatus(any())).thenReturn(createDisputeStatusSuccessResult());
when(providerDisputesThriftInterfaceBuilder.buildWoodyClient(any())).thenReturn(providerMock);
var providerPaymentMock = mock(ProviderPaymentsServiceSrv.Client.class);
when(providerPaymentMock.checkPaymentStatus(any(), any())).thenReturn(new PaymentStatusResult(true));
when(providerPaymentMock.checkPaymentStatus(any(), any())).thenReturn(paymentStatusResult);
when(providerPaymentsThriftInterfaceBuilder.buildWoodyClient(any())).thenReturn(providerPaymentMock);
var dispute = disputeDao.get(disputeId);
pendingDisputesService.callPendingDisputeRemotely(dispute);
Expand Down
12 changes: 12 additions & 0 deletions src/test/java/dev/vality/disputes/util/MockUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,18 @@ public static InvoicePaymentAdjustment getCashFlowInvoicePaymentAdjustment(Strin
.setScenario(new InvoicePaymentAdjustmentCashFlow().setNewAmount(10L))));
}

public static InvoicePaymentAdjustment getTransactionInfoInvoicePaymentAdjustment(
String adjustmentId,
String reason,
TransactionInfo transactionInfo) {
return new InvoicePaymentAdjustment()
.setId(adjustmentId)
.setReason(reason)
.setState(InvoicePaymentAdjustmentState.transaction_info(
new InvoicePaymentAdjustmentTransactionInfoState()
.setScenario(new InvoicePaymentAdjustmentTransactionInfo(transactionInfo))));
}

public static Failure createFailure() {
Failure failure = new Failure("no_transfer");
failure.setReason("code = resp_status_error, description = Tek seferde en fazla 4,000.00 işem yapılabilir.");
Expand Down
Loading