diff --git a/src/main/java/dev/vality/disputes/callback/ProviderDisputesCallbackHandler.java b/src/main/java/dev/vality/disputes/callback/ProviderDisputesCallbackHandler.java new file mode 100644 index 0000000..781acfe --- /dev/null +++ b/src/main/java/dev/vality/disputes/callback/ProviderDisputesCallbackHandler.java @@ -0,0 +1,47 @@ +package dev.vality.disputes.callback; + +import dev.vality.disputes.dao.DisputeDao; +import dev.vality.disputes.dao.ProviderDisputeDao; +import dev.vality.disputes.schedule.handler.DisputeStatusResultHandler; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.thrift.TException; +import org.springframework.stereotype.Service; + +import java.util.Objects; + +import static dev.vality.disputes.api.service.ApiDisputesService.DISPUTE_PENDING; + +@Service +@RequiredArgsConstructor +@Slf4j +@SuppressWarnings({"ParameterName", "LineLength", "MissingSwitchDefault"}) +public class ProviderDisputesCallbackHandler implements ProviderDisputesCallbackServiceSrv.Iface { + + private final DisputeDao disputeDao; + private final ProviderDisputeDao providerDisputeDao; + private final DisputeStatusResultHandler disputeStatusResultHandler; + + @Override + public void changeStatus(DisputeCallbackParams disputeCallbackParams) throws TException { + var transactionContext = disputeCallbackParams.getTransactionContext(); + var disputes = disputeDao.get(transactionContext.getInvoiceId(), transactionContext.getPaymentId()); + var optionalDispute = disputes.stream() + .filter(d -> DISPUTE_PENDING.contains(d.getStatus())) + .findFirst(); + if (optionalDispute.isEmpty()) { + return; + } + var dispute = optionalDispute.get(); + var providerDispute = providerDisputeDao.get(dispute.getId()); + if (providerDispute == null + || !Objects.equals(providerDispute.getProviderDisputeId(), disputeCallbackParams.getProviderDisputeId())) { + return; + } + var result = disputeCallbackParams.getDisputeStatusResult(); + switch (result.getSetField()) { + case STATUS_SUCCESS -> disputeStatusResultHandler.handleStatusSuccess(dispute, result); + case STATUS_FAIL -> disputeStatusResultHandler.handleStatusFail(dispute, result); + } + } +} diff --git a/src/main/java/dev/vality/disputes/schedule/handler/DisputeStatusResultHandler.java b/src/main/java/dev/vality/disputes/schedule/handler/DisputeStatusResultHandler.java new file mode 100644 index 0000000..03d3351 --- /dev/null +++ b/src/main/java/dev/vality/disputes/schedule/handler/DisputeStatusResultHandler.java @@ -0,0 +1,50 @@ +package dev.vality.disputes.schedule.handler; + +import dev.vality.disputes.DisputeStatusResult; +import dev.vality.disputes.dao.DisputeDao; +import dev.vality.disputes.domain.enums.DisputeStatus; +import dev.vality.disputes.domain.tables.pojos.Dispute; +import dev.vality.disputes.polling.ExponentialBackOffPollingServiceWrapper; +import dev.vality.geck.serializer.kit.tbase.TErrorUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@RequiredArgsConstructor +@SuppressWarnings({"ParameterName", "LineLength", "MissingSwitchDefault"}) +public class DisputeStatusResultHandler { + + private final DisputeDao disputeDao; + private final ExponentialBackOffPollingServiceWrapper exponentialBackOffPollingService; + + @Transactional(propagation = Propagation.REQUIRED) + public void handleStatusPending(Dispute dispute, DisputeStatusResult result) { + // дергаем update() чтоб обновить время вызова next_check_after, + // чтобы шедулатор далее доставал пачку самых древних диспутов и смещал + // и этим вызовом мы финализируем состояние диспута, что он был обновлен недавно + var nextCheckAfter = exponentialBackOffPollingService.prepareNextPollingInterval(dispute); + log.info("Trying to set pending Dispute status {}, {}", dispute, result); + disputeDao.update(dispute.getId(), DisputeStatus.pending, nextCheckAfter); + log.debug("Dispute status has been set to pending {}", dispute.getId()); + } + + @Transactional(propagation = Propagation.REQUIRED) + public void handleStatusFail(Dispute dispute, DisputeStatusResult result) { + var errorMessage = TErrorUtil.toStringVal(result.getStatusFail().getFailure()); + log.warn("Trying to set failed Dispute status {}, {}", dispute.getId(), errorMessage); + disputeDao.update(dispute.getId(), DisputeStatus.failed, errorMessage); + log.debug("Dispute status has been set to failed {}", dispute.getId()); + } + + @Transactional(propagation = Propagation.REQUIRED) + public void handleStatusSuccess(Dispute dispute, DisputeStatusResult result) { + var changedAmount = result.getStatusSuccess().getChangedAmount().orElse(null); + log.info("Trying to set create_adjustment Dispute status {}, {}", dispute, result); + disputeDao.update(dispute.getId(), DisputeStatus.create_adjustment, changedAmount); + log.debug("Dispute status has been set to create_adjustment {}", dispute.getId()); + } +} diff --git a/src/main/java/dev/vality/disputes/schedule/service/PendingDisputesService.java b/src/main/java/dev/vality/disputes/schedule/service/PendingDisputesService.java index 9736446..d6e3682 100644 --- a/src/main/java/dev/vality/disputes/schedule/service/PendingDisputesService.java +++ b/src/main/java/dev/vality/disputes/schedule/service/PendingDisputesService.java @@ -9,7 +9,7 @@ import dev.vality.disputes.domain.tables.pojos.Dispute; import dev.vality.disputes.polling.ExponentialBackOffPollingServiceWrapper; import dev.vality.disputes.polling.PollingInfoService; import dev.vality.disputes.schedule.client.RemoteClient; -import dev.vality.geck.serializer.kit.tbase.TErrorUtil; +import dev.vality.disputes.schedule.handler.DisputeStatusResultHandler; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -30,6 +30,7 @@ public class PendingDisputesService { private final ProviderDisputeDao providerDisputeDao; private final PollingInfoService pollingInfoService; private final ExponentialBackOffPollingServiceWrapper exponentialBackOffPollingService; + private final DisputeStatusResultHandler disputeStatusResultHandler; @Transactional(propagation = Propagation.REQUIRED) public List getPendingDisputesForUpdateSkipLocked(int batchSize) { @@ -72,27 +73,9 @@ public class PendingDisputesService { @Transactional(propagation = Propagation.REQUIRED) void finishTask(Dispute dispute, DisputeStatusResult result) { switch (result.getSetField()) { - case STATUS_SUCCESS -> { - var changedAmount = result.getStatusSuccess().getChangedAmount().orElse(null); - log.info("Trying to set create_adjustment Dispute status {}, {}", dispute, result); - disputeDao.update(dispute.getId(), DisputeStatus.create_adjustment, changedAmount); - log.debug("Dispute status has been set to create_adjustment {}", dispute.getId()); - } - case STATUS_FAIL -> { - var errorMessage = TErrorUtil.toStringVal(result.getStatusFail().getFailure()); - log.warn("Trying to set failed Dispute status {}, {}", dispute.getId(), errorMessage); - disputeDao.update(dispute.getId(), DisputeStatus.failed, errorMessage); - log.debug("Dispute status has been set to failed {}", dispute.getId()); - } - case STATUS_PENDING -> { - // дергаем update() чтоб обновить время вызова next_check_after, - // чтобы шедулатор далее доставал пачку самых древних диспутов и смещал - // и этим вызовом мы финализируем состояние диспута, что он был обновлен недавно - var nextCheckAfter = exponentialBackOffPollingService.prepareNextPollingInterval(dispute); - log.info("Trying to set pending Dispute status {}, {}", dispute, result); - disputeDao.update(dispute.getId(), DisputeStatus.pending, nextCheckAfter); - log.debug("Dispute status has been set to pending {}", dispute.getId()); - } + case STATUS_SUCCESS -> disputeStatusResultHandler.handleStatusSuccess(dispute, result); + case STATUS_FAIL -> disputeStatusResultHandler.handleStatusFail(dispute, result); + case STATUS_PENDING -> disputeStatusResultHandler.handleStatusPending(dispute, result); } } } diff --git a/src/main/java/dev/vality/disputes/servlet/ManualParsingServlet.java b/src/main/java/dev/vality/disputes/servlet/ManualParsingServlet.java index 13a4683..502770c 100644 --- a/src/main/java/dev/vality/disputes/servlet/ManualParsingServlet.java +++ b/src/main/java/dev/vality/disputes/servlet/ManualParsingServlet.java @@ -8,7 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired; import java.io.IOException; -@WebServlet("/disputes-api/manual-parsing") +@WebServlet("/disputes-api/v1/manual-parsing") public class ManualParsingServlet extends GenericServlet { @Autowired diff --git a/src/main/java/dev/vality/disputes/servlet/ProviderDisputesCallbackServlet.java b/src/main/java/dev/vality/disputes/servlet/ProviderDisputesCallbackServlet.java new file mode 100644 index 0000000..7b66cdc --- /dev/null +++ b/src/main/java/dev/vality/disputes/servlet/ProviderDisputesCallbackServlet.java @@ -0,0 +1,30 @@ +package dev.vality.disputes.servlet; + +import dev.vality.disputes.callback.ProviderDisputesCallbackServiceSrv; +import dev.vality.woody.thrift.impl.http.THServiceBuilder; +import jakarta.servlet.*; +import jakarta.servlet.annotation.WebServlet; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.IOException; + +@WebServlet("/disputes-api/v1/callback") +public class ProviderDisputesCallbackServlet extends GenericServlet { + + @Autowired + private ProviderDisputesCallbackServiceSrv.Iface providerDisputesCallbackHandler; + + private Servlet servlet; + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + servlet = new THServiceBuilder() + .build(ProviderDisputesCallbackServiceSrv.Iface.class, providerDisputesCallbackHandler); + } + + @Override + public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { + servlet.service(request, response); + } +}