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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import dev.vality.adapter.flow.lib.model.PollingInfo;
import dev.vality.disputes.domain.tables.pojos.Dispute;
import dev.vality.disputes.domain.tables.pojos.Notification;
import dev.vality.disputes.domain.tables.pojos.ProviderCallback;
import org.springframework.stereotype.Service;

import java.time.Instant;
Expand Down Expand Up @@ -41,6 +42,14 @@ public LocalDateTime prepareNextPollingInterval(Notification notification, Local
notification.getNextAttemptAfter().toInstant(ZoneOffset.UTC).plusSeconds(seconds));
}

public LocalDateTime prepareNextPollingInterval(ProviderCallback providerCallback, Map<String, String> options) {
var pollingInfo = new PollingInfo();
pollingInfo.setStartDateTimePolling(providerCallback.getCreatedAt().toInstant(ZoneOffset.UTC));
var seconds = exponentialBackOffPollingService.prepareNextPollingInterval(pollingInfo, options);
return getLocalDateTime(
providerCallback.getNextCheckAfter().toInstant(ZoneOffset.UTC).plusSeconds(seconds));
}

private LocalDateTime getLocalDateTime(Instant instant) {
return LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
Expand Down Expand Up @@ -59,7 +61,9 @@ public ProviderCallback get(String invoiceId, String paymentId) {

public List<ProviderCallback> getProviderCallbacksForHgCall(int limit) {
var query = getDslContext().selectFrom(PROVIDER_CALLBACK)
.where(PROVIDER_CALLBACK.STATUS.eq(ProviderPaymentsStatus.create_adjustment))
.where(PROVIDER_CALLBACK.STATUS.eq(ProviderPaymentsStatus.create_adjustment)
.and(PROVIDER_CALLBACK.NEXT_CHECK_AFTER.le(LocalDateTime.now(ZoneOffset.UTC))))
.orderBy(PROVIDER_CALLBACK.NEXT_CHECK_AFTER)
.limit(limit)
.forUpdate()
.skipLocked();
Expand All @@ -74,4 +78,11 @@ var record = getDslContext().newRecord(PROVIDER_CALLBACK, providerCallback);
.where(PROVIDER_CALLBACK.ID.eq(providerCallback.getId()));
execute(query);
}

public void updateNextCheckAfter(UUID id, LocalDateTime nextCheckAfter) {
var query = getDslContext().update(PROVIDER_CALLBACK)
.set(PROVIDER_CALLBACK.NEXT_CHECK_AFTER, nextCheckAfter)
.where(PROVIDER_CALLBACK.ID.eq(id));
execute(query);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import dev.vality.disputes.exception.InvoicingPaymentStatusRestrictionsException;
import dev.vality.disputes.exception.NotFoundException;
import dev.vality.disputes.exception.ProviderTrxIdNotFoundException;
import dev.vality.disputes.polling.ExponentialBackOffPollingServiceWrapper;
import dev.vality.disputes.provider.payments.client.ProviderPaymentsRemoteClient;
import dev.vality.disputes.provider.payments.converter.ProviderPaymentsToInvoicePaymentCapturedAdjustmentParamsConverter;
import dev.vality.disputes.provider.payments.converter.ProviderPaymentsToInvoicePaymentCashFlowAdjustmentParamsConverter;
Expand All @@ -35,6 +36,7 @@

import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static dev.vality.disputes.constant.ErrorMessage.INVOICE_NOT_FOUND;
Expand All @@ -60,6 +62,7 @@ public class ProviderPaymentsService {
private final DisputesService disputesService;
private final ProviderPaymentsRemoteClient providerPaymentsRemoteClient;
private final ProviderPaymentsCheckStatusScheduler providerPaymentsCheckStatusScheduler;
private final ExponentialBackOffPollingServiceWrapper exponentialBackOffPollingService;

@Async("disputesAsyncServiceExecutor")
public void processCallback(ProviderPaymentsCallbackParams callback) {
Expand Down Expand Up @@ -177,6 +180,7 @@ public void callHgForCreateAdjustment(ProviderCallback providerCallback) {
if (statusAction == PaymentStatusValidator.StatusAction.WAIT) {
log.info("Invoice payment is not final, retry create adjustment later, invoiceId={}, paymentId={}",
providerCallback.getInvoiceId(), providerCallback.getPaymentId());
updateNextCheckAfter(providerCallback);
return;
}
if (statusAction == PaymentStatusValidator.StatusAction.FAILED) {
Expand Down Expand Up @@ -251,6 +255,13 @@ private void checkCreateAdjustmentStatus(ProviderCallback providerCallback) {
}
}

private void updateNextCheckAfter(ProviderCallback providerCallback) {
var nextCheckAfter = exponentialBackOffPollingService.prepareNextPollingInterval(providerCallback, Map.of());
log.info("Trying to update ProviderCallback nextCheckAfter {}", providerCallback);
providerCallbackDao.updateNextCheckAfter(providerCallback.getId(), nextCheckAfter);
log.debug("ProviderCallback nextCheckAfter has been updated {}", providerCallback.getInvoiceId());
}

private boolean createCashFlowAdjustment(ProviderCallback providerCallback, InvoicePayment invoicePayment) {
var cashFlowAdjustmentExists = providerPaymentsAdjustmentExtractor.isCashFlowAdjustmentByProviderPaymentsExist(
invoicePayment,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public void callCreateDisputeRemotely(Dispute dispute) {
if (statusAction == PaymentStatusValidator.StatusAction.WAIT) {
log.info("Invoice payment is not final, retry create dispute later, invoiceId={}, paymentId={}",
dispute.getInvoiceId(), dispute.getPaymentId());
disputesService.setNextStepToCreated(dispute);
Comment thread
echerniak marked this conversation as resolved.
return;
}
if (statusAction == PaymentStatusValidator.StatusAction.SUCCEEDED) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public void process(Dispute dispute) {
if (statusAction == PaymentStatusValidator.StatusAction.WAIT) {
log.info("Invoice payment is not final, retry forgotten dispute later, invoiceId={}, paymentId={}",
dispute.getInvoiceId(), dispute.getPaymentId());
disputesService.updateNextPollingInterval(dispute);
return;
}
if (statusAction == PaymentStatusValidator.StatusAction.SUCCEEDED) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public void callPendingDisputeRemotely(Dispute dispute) {
if (statusAction == PaymentStatusValidator.StatusAction.WAIT) {
log.info("Invoice payment is not final, retry pending dispute later, invoiceId={}, paymentId={}",
dispute.getInvoiceId(), dispute.getPaymentId());
disputesService.setNextStepToPending(dispute);
return;
}
if (statusAction == PaymentStatusValidator.StatusAction.SUCCEEDED) {
Expand Down
31 changes: 28 additions & 3 deletions src/main/java/dev/vality/disputes/service/DisputesService.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
Expand Down Expand Up @@ -72,17 +73,33 @@ public void finishCancelled(Dispute dispute, String mapping, String providerMess
}

public void setNextStepToCreated(Dispute dispute, ProviderData providerData) {
setNextStepToCreated(dispute, providerData.getOptions());
}

public void setNextStepToCreated(Dispute dispute) {
setNextStepToCreated(dispute, Map.of());
}

private void setNextStepToCreated(Dispute dispute, Map<String, String> options) {
var nextCheckAfter =
exponentialBackOffPollingService.prepareNextPollingInterval(dispute, providerData.getOptions());
exponentialBackOffPollingService.prepareNextPollingInterval(dispute, options);
log.info("Trying to set created Dispute status {}", dispute.getId());
disputeDao.setNextStepToCreated(dispute.getId(), nextCheckAfter);
log.debug("Dispute status has been set to created {}", dispute.getId());
callbackNotifier.notify(disputeDao.get(dispute.getId()));
}

public void setNextStepToPending(Dispute dispute, ProviderData providerData) {
setNextStepToPending(dispute, providerData.getOptions());
}

public void setNextStepToPending(Dispute dispute) {
setNextStepToPending(dispute, Map.of());
}

private void setNextStepToPending(Dispute dispute, Map<String, String> options) {
var nextCheckAfter =
exponentialBackOffPollingService.prepareNextPollingInterval(dispute, providerData.getOptions());
exponentialBackOffPollingService.prepareNextPollingInterval(dispute, options);
log.info("Trying to set pending Dispute status {}", dispute);
disputeDao.setNextStepToPending(dispute.getId(), nextCheckAfter, dispute.getPollingBefore());
log.debug("Dispute status has been set to pending {}", dispute.getId());
Expand Down Expand Up @@ -119,8 +136,16 @@ public void setNextStepToPoolingExpired(Dispute dispute) {
}

public void updateNextPollingInterval(Dispute dispute, ProviderData providerData) {
updateNextPollingInterval(dispute, providerData.getOptions());
}

public void updateNextPollingInterval(Dispute dispute) {
updateNextPollingInterval(dispute, Map.of());
}

private void updateNextPollingInterval(Dispute dispute, Map<String, String> options) {
var nextCheckAfter =
exponentialBackOffPollingService.prepareNextPollingInterval(dispute, providerData.getOptions());
exponentialBackOffPollingService.prepareNextPollingInterval(dispute, options);
disputeDao.updateNextPollingInterval(dispute, nextCheckAfter);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE dspt.provider_callback
ADD COLUMN "next_check_after" TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT (now() at time zone 'utc');

CREATE INDEX provider_callback_status_next_check_after_idx
ON dspt.provider_callback USING btree (status, next_check_after);
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import static dev.vality.disputes.util.MockUtil.createInvoicePayment;
import static org.junit.jupiter.api.Assertions.assertEquals;
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.verify;
Expand Down Expand Up @@ -76,8 +77,10 @@ public void testRetryLaterWhenInvoicePaymentStatusIsPending() {

providerPaymentsService.callHgForCreateAdjustment(providerCallback);

var nextCheckAfter = providerCallback.getNextCheckAfter();
providerCallback = providerCallbackDao.get(dispute.getInvoiceId(), dispute.getPaymentId());
assertEquals(ProviderPaymentsStatus.create_adjustment, providerCallback.getStatus());
assertTrue(providerCallback.getNextCheckAfter().isAfter(nextCheckAfter));
assertEquals(DisputeStatus.create_adjustment, disputeDao.get(disputeId).getStatus());
verify(invoicingClient, never()).createPaymentAdjustment(any(), any(), any());
}
Expand All @@ -94,8 +97,10 @@ public void testRetryLaterWhenInvoicePaymentStatusIsProcessed() {

providerPaymentsService.callHgForCreateAdjustment(providerCallback);

var nextCheckAfter = providerCallback.getNextCheckAfter();
providerCallback = providerCallbackDao.get(dispute.getInvoiceId(), dispute.getPaymentId());
assertEquals(ProviderPaymentsStatus.create_adjustment, providerCallback.getStatus());
assertTrue(providerCallback.getNextCheckAfter().isAfter(nextCheckAfter));
assertEquals(DisputeStatus.create_adjustment, disputeDao.get(disputeId).getStatus());
verify(invoicingClient, never()).createPaymentAdjustment(any(), any(), any());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,9 @@ public void testWaitWhenInvoicePaymentStatusIsPending() {
var disputeId = UUID.fromString(merchantApiMvcPerformer.createDispute(invoiceId, paymentId).getDisputeId());
var dispute = disputeDao.get(disputeId);
createdDisputesService.callCreateDisputeRemotely(dispute);
assertEquals(DisputeStatus.created, disputeDao.get(disputeId).getStatus());
var updatedDispute = disputeDao.get(disputeId);
assertEquals(DisputeStatus.created, updatedDispute.getStatus());
assertTrue(updatedDispute.getNextCheckAfter().isAfter(dispute.getNextCheckAfter()));
disputeDao.finishFailed(disputeId, null);
}

Expand All @@ -281,7 +283,9 @@ public void testWaitWhenInvoicePaymentStatusIsProcessed() {
var disputeId = UUID.fromString(merchantApiMvcPerformer.createDispute(invoiceId, paymentId).getDisputeId());
var dispute = disputeDao.get(disputeId);
createdDisputesService.callCreateDisputeRemotely(dispute);
assertEquals(DisputeStatus.created, disputeDao.get(disputeId).getStatus());
var updatedDispute = disputeDao.get(disputeId);
assertEquals(DisputeStatus.created, updatedDispute.getStatus());
assertTrue(updatedDispute.getNextCheckAfter().isAfter(dispute.getNextCheckAfter()));
disputeDao.finishFailed(disputeId, null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static dev.vality.disputes.util.MockUtil.createInvoicePayment;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -69,7 +70,9 @@ public void testWaitWhenInvoicePaymentStatusIsPending() {
invoicePayment.getPayment().setStatus(InvoicePaymentStatus.pending(new InvoicePaymentPending()));
when(invoicingClient.getPayment(any(), any())).thenReturn(invoicePayment);
forgottenDisputesService.process(dispute);
assertEquals(DisputeStatus.pending, disputeDao.get(disputeId).getStatus());
var updatedDispute = disputeDao.get(disputeId);
assertEquals(DisputeStatus.pending, updatedDispute.getStatus());
assertTrue(updatedDispute.getNextCheckAfter().isAfter(dispute.getNextCheckAfter()));
}

@Test
Expand All @@ -81,7 +84,9 @@ public void testWaitWhenInvoicePaymentStatusIsProcessed() {
invoicePayment.getPayment().setStatus(InvoicePaymentStatus.processed(new InvoicePaymentProcessed()));
when(invoicingClient.getPayment(any(), any())).thenReturn(invoicePayment);
forgottenDisputesService.process(dispute);
assertEquals(DisputeStatus.pending, disputeDao.get(disputeId).getStatus());
var updatedDispute = disputeDao.get(disputeId);
assertEquals(DisputeStatus.pending, updatedDispute.getStatus());
assertTrue(updatedDispute.getNextCheckAfter().isAfter(dispute.getNextCheckAfter()));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@ public void testPendingWhenInvoicePaymentStatusIsPending() {
invoicePayment.getPayment().setStatus(InvoicePaymentStatus.pending(new InvoicePaymentPending()));
when(invoicingClient.getPayment(any(), any())).thenReturn(invoicePayment);
pendingDisputesService.callPendingDisputeRemotely(dispute);
assertEquals(DisputeStatus.pending, disputeDao.get(disputeId).getStatus());
var updatedDispute = disputeDao.get(disputeId);
assertEquals(DisputeStatus.pending, updatedDispute.getStatus());
assertTrue(updatedDispute.getNextCheckAfter().isAfter(dispute.getNextCheckAfter()));
disputeDao.finishFailed(disputeId, null);
}

Expand All @@ -205,7 +207,9 @@ public void testPendingWhenInvoicePaymentStatusIsProcessed() {
invoicePayment.getPayment().setStatus(InvoicePaymentStatus.processed(new InvoicePaymentProcessed()));
when(invoicingClient.getPayment(any(), any())).thenReturn(invoicePayment);
pendingDisputesService.callPendingDisputeRemotely(dispute);
assertEquals(DisputeStatus.pending, disputeDao.get(disputeId).getStatus());
var updatedDispute = disputeDao.get(disputeId);
assertEquals(DisputeStatus.pending, updatedDispute.getStatus());
assertTrue(updatedDispute.getNextCheckAfter().isAfter(dispute.getNextCheckAfter()));
disputeDao.finishFailed(disputeId, null);
}
}
Loading