mirror of
https://github.com/valitydev/disputes-api.git
synced 2024-11-06 00:55:23 +00:00
fixes, add already_exist_created flow, add GetDispute handler (#9)
This commit is contained in:
parent
7c61521a9a
commit
6faacd9ac1
2
.github/workflows/deploy.yml
vendored
2
.github/workflows/deploy.yml
vendored
@ -4,6 +4,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master'
|
||||||
|
- 'main'
|
||||||
|
- 'epic/**'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-deploy:
|
build-and-deploy:
|
||||||
|
@ -115,15 +115,15 @@
|
|||||||
|
|
||||||
- Перед переводом диспута в финальный статус саппорт должен будет забиндить айди созданного диспута в провайдере через
|
- Перед переводом диспута в финальный статус саппорт должен будет забиндить айди созданного диспута в провайдере через
|
||||||
ручку `BindCreated()`. Здесь особенность, что этот метод фильтрует возможность биндить диспуты только созданные
|
ручку `BindCreated()`. Здесь особенность, что этот метод фильтрует возможность биндить диспуты только созданные
|
||||||
вручную (из `manual_parsing_created`)
|
вручную (из `manual_created`)
|
||||||
|
|
||||||
Далее, в режиме ручного разбора есть опция финализации диспута в фейл (`CancelPending()`) либо в
|
Далее, в режиме ручного разбора есть опция финализации диспута в фейл (`CancelPending()`) либо в
|
||||||
успех (`ApprovePending()`). Здесь особенность, что в фейл можно перевести любой диспут имеющий не финальный статус, а в
|
успех (`ApprovePending()`). Здесь особенность, что в фейл можно перевести любой диспут имеющий не финальный статус, а в
|
||||||
успех можно перевести, только если гарантировано создан внешний диспут у провайдера (
|
успех можно перевести, только если гарантировано создан внешний диспут у провайдера (
|
||||||
из `pending`,`manual_parsing_binded_pending`)
|
из `pending`,`manual_pending`)
|
||||||
|
|
||||||
- Из за того, что для ручных диспутов добавлены отдельные
|
- Из за того, что для ручных диспутов добавлены отдельные
|
||||||
статусы `manual_parsing_binded_pending` ,`manual_parsing_created` не происходит ситуации, что такие диспуты попадут в
|
статусы `manual_pending` ,`manual_created` не происходит ситуации, что такие диспуты попадут в
|
||||||
таску `PendingDisputesService` которая автоматически вызывает апи провайдера для проверки статуса
|
таску `PendingDisputesService` которая автоматически вызывает апи провайдера для проверки статуса
|
||||||
|
|
||||||
# Схема аппрува корректировок
|
# Схема аппрува корректировок
|
||||||
|
10
pom.xml
10
pom.xml
@ -47,7 +47,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>dev.vality</groupId>
|
<groupId>dev.vality</groupId>
|
||||||
<artifactId>provider-disputes-proto</artifactId>
|
<artifactId>provider-disputes-proto</artifactId>
|
||||||
<version>1.16-61eff7c</version>
|
<version>1.18-6602d79</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>dev.vality</groupId>
|
<groupId>dev.vality</groupId>
|
||||||
@ -89,10 +89,6 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--spring-->
|
<!--spring-->
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-aop</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||||
@ -193,6 +189,10 @@
|
|||||||
<version>3.0.2</version>
|
<version>3.0.2</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openapitools</groupId>
|
<groupId>org.openapitools</groupId>
|
||||||
<artifactId>jackson-databind-nullable</artifactId>
|
<artifactId>jackson-databind-nullable</artifactId>
|
||||||
|
@ -4,8 +4,10 @@ import org.springframework.boot.SpringApplication;
|
|||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.web.servlet.ServletComponentScan;
|
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||||
import org.springframework.scheduling.annotation.EnableAsync;
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
@EnableAsync
|
@EnableAsync
|
||||||
|
@EnableScheduling
|
||||||
@ServletComponentScan
|
@ServletComponentScan
|
||||||
@SpringBootApplication(scanBasePackages = {"dev.vality.disputes", "dev.vality.swag"})
|
@SpringBootApplication(scanBasePackages = {"dev.vality.disputes", "dev.vality.swag"})
|
||||||
public class DisputesApiApplication extends SpringApplication {
|
public class DisputesApiApplication extends SpringApplication {
|
||||||
|
@ -23,7 +23,7 @@ public class Status200ResponseConverter {
|
|||||||
|
|
||||||
private Status200Response.StatusEnum getStatus(Dispute dispute) {
|
private Status200Response.StatusEnum getStatus(Dispute dispute) {
|
||||||
return switch (dispute.getStatus()) {
|
return switch (dispute.getStatus()) {
|
||||||
case created, pending, manual_created, manual_pending, create_adjustment ->
|
case created, pending, manual_created, manual_pending, create_adjustment, already_exist_created ->
|
||||||
Status200Response.StatusEnum.PENDING;
|
Status200Response.StatusEnum.PENDING;
|
||||||
case succeeded -> Status200Response.StatusEnum.SUCCEEDED;
|
case succeeded -> Status200Response.StatusEnum.SUCCEEDED;
|
||||||
case cancelled, failed -> Status200Response.StatusEnum.FAILED;
|
case cancelled, failed -> Status200Response.StatusEnum.FAILED;
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
package dev.vality.disputes.api.model;
|
package dev.vality.disputes.api.model;
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Data;
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Builder
|
@Builder
|
||||||
@Getter
|
@Data
|
||||||
@Setter
|
|
||||||
public class PaymentParams {
|
public class PaymentParams {
|
||||||
|
|
||||||
private String invoiceId;
|
private String invoiceId;
|
||||||
|
@ -4,7 +4,6 @@ import dev.vality.disputes.dao.FileMetaDao;
|
|||||||
import dev.vality.disputes.domain.tables.pojos.FileMeta;
|
import dev.vality.disputes.domain.tables.pojos.FileMeta;
|
||||||
import dev.vality.disputes.service.external.FileStorageService;
|
import dev.vality.disputes.service.external.FileStorageService;
|
||||||
import dev.vality.swag.disputes.model.CreateRequest;
|
import dev.vality.swag.disputes.model.CreateRequest;
|
||||||
import dev.vality.swag.disputes.model.CreateRequestAttachmentsInner;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@ -24,13 +23,13 @@ public class ApiAttachmentsService {
|
|||||||
@Transactional(propagation = Propagation.REQUIRED)
|
@Transactional(propagation = Propagation.REQUIRED)
|
||||||
public void createAttachments(CreateRequest req, Long disputeId) {
|
public void createAttachments(CreateRequest req, Long disputeId) {
|
||||||
log.debug("Trying to save Attachments {}", disputeId);
|
log.debug("Trying to save Attachments {}", disputeId);
|
||||||
for (CreateRequestAttachmentsInner attachment : req.getAttachments()) {
|
for (var attachment : req.getAttachments()) {
|
||||||
// validate
|
// validate
|
||||||
MediaType.valueOf(attachment.getMimeType());
|
MediaType.valueOf(attachment.getMimeType());
|
||||||
// http 500
|
// http 500
|
||||||
var fileId = fileStorageService.saveFile(attachment.getData());
|
var fileId = fileStorageService.saveFile(attachment.getData());
|
||||||
var fileMeta = new FileMeta(fileId, disputeId, attachment.getMimeType());
|
var fileMeta = new FileMeta(fileId, disputeId, attachment.getMimeType());
|
||||||
log.debug("Trying to save Attachment {}", fileMeta.getFileId());
|
log.debug("Trying to save Attachment {}", fileMeta);
|
||||||
// http 500
|
// http 500
|
||||||
fileMetaDao.save(fileMeta);
|
fileMetaDao.save(fileMeta);
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,7 @@ public class ApiDisputesService {
|
|||||||
DisputeStatus.pending,
|
DisputeStatus.pending,
|
||||||
DisputeStatus.manual_created,
|
DisputeStatus.manual_created,
|
||||||
DisputeStatus.manual_pending,
|
DisputeStatus.manual_pending,
|
||||||
DisputeStatus.create_adjustment);
|
DisputeStatus.create_adjustment,
|
||||||
|
DisputeStatus.already_exist_created);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,21 @@ import dev.vality.damsel.domain.TransactionInfo;
|
|||||||
import dev.vality.damsel.payment_processing.InvoicePayment;
|
import dev.vality.damsel.payment_processing.InvoicePayment;
|
||||||
import dev.vality.disputes.api.model.PaymentParams;
|
import dev.vality.disputes.api.model.PaymentParams;
|
||||||
import dev.vality.disputes.security.AccessData;
|
import dev.vality.disputes.security.AccessData;
|
||||||
import dev.vality.disputes.service.external.DominantService;
|
import dev.vality.disputes.service.external.impl.dominant.DominantAsyncService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class PaymentParamsBuilder {
|
public class PaymentParamsBuilder {
|
||||||
|
|
||||||
private final DominantService dominantService;
|
private final DominantAsyncService dominantAsyncService;
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public PaymentParams buildGeneralPaymentContext(AccessData accessData) {
|
public PaymentParams buildGeneralPaymentContext(AccessData accessData) {
|
||||||
@ -26,28 +27,42 @@ public class PaymentParamsBuilder {
|
|||||||
log.debug("Start building PaymentParams id={}", invoice.getInvoice().getId());
|
log.debug("Start building PaymentParams id={}", invoice.getInvoice().getId());
|
||||||
var payment = accessData.getPayment();
|
var payment = accessData.getPayment();
|
||||||
// http 500
|
// http 500
|
||||||
var terminal = dominantService.getTerminal(payment.getRoute().getTerminal());
|
var terminal = dominantAsyncService.getTerminal(payment.getRoute().getTerminal());
|
||||||
var currency = Optional.of(payment)
|
var currency = Optional.of(payment)
|
||||||
.filter(p -> p.getPayment().isSetCost())
|
.filter(p -> p.getPayment().isSetCost())
|
||||||
.map(p -> p.getPayment().getCost())
|
.map(p -> p.getPayment().getCost())
|
||||||
// http 500
|
// http 500
|
||||||
.map(cost -> dominantService.getCurrency(cost.getCurrency()));
|
.map(cost -> dominantAsyncService.getCurrency(cost.getCurrency()));
|
||||||
var paymentParams = PaymentParams.builder()
|
var paymentParams = PaymentParams.builder()
|
||||||
.invoiceId(invoice.getInvoice().getId())
|
.invoiceId(invoice.getInvoice().getId())
|
||||||
.paymentId(payment.getPayment().getId())
|
.paymentId(payment.getPayment().getId())
|
||||||
.terminalId(payment.getRoute().getTerminal().getId())
|
.terminalId(payment.getRoute().getTerminal().getId())
|
||||||
.providerId(payment.getRoute().getProvider().getId())
|
.providerId(payment.getRoute().getProvider().getId())
|
||||||
.providerTrxId(getProviderTrxId(payment))
|
.providerTrxId(getProviderTrxId(payment))
|
||||||
.currencyName(currency.map(Currency::getName).orElse(null))
|
.currencyName(getCurrency(currency)
|
||||||
.currencySymbolicCode(currency.map(Currency::getSymbolicCode).orElse(null))
|
.map(Currency::getName).orElse(null))
|
||||||
.currencyNumericCode(currency.map(Currency::getNumericCode).map(Short::intValue).orElse(null))
|
.currencySymbolicCode(getCurrency(currency)
|
||||||
.currencyExponent(currency.map(Currency::getExponent).map(Short::intValue).orElse(null))
|
.map(Currency::getSymbolicCode).orElse(null))
|
||||||
|
.currencyNumericCode(getCurrency(currency)
|
||||||
|
.map(Currency::getNumericCode).map(Short::intValue).orElse(null))
|
||||||
|
.currencyExponent(getCurrency(currency)
|
||||||
|
.map(Currency::getExponent).map(Short::intValue).orElse(null))
|
||||||
.options(terminal.get().getOptions())
|
.options(terminal.get().getOptions())
|
||||||
.build();
|
.build();
|
||||||
log.debug("Finish building PaymentParams {}", paymentParams);
|
log.debug("Finish building PaymentParams {}", paymentParams);
|
||||||
return paymentParams;
|
return paymentParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<Currency> getCurrency(Optional<CompletableFuture<Currency>> currency) {
|
||||||
|
return currency.map(currencyCompletableFuture -> {
|
||||||
|
try {
|
||||||
|
return currencyCompletableFuture.get();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private String getProviderTrxId(InvoicePayment payment) {
|
private String getProviderTrxId(InvoicePayment payment) {
|
||||||
return Optional.ofNullable(payment.getLastTransactionInfo())
|
return Optional.ofNullable(payment.getLastTransactionInfo())
|
||||||
.map(TransactionInfo::getId)
|
.map(TransactionInfo::getId)
|
||||||
|
@ -7,8 +7,6 @@ import dev.vality.damsel.payment_processing.InvoicingSrv;
|
|||||||
import dev.vality.file.storage.FileStorageSrv;
|
import dev.vality.file.storage.FileStorageSrv;
|
||||||
import dev.vality.token.keeper.TokenAuthenticatorSrv;
|
import dev.vality.token.keeper.TokenAuthenticatorSrv;
|
||||||
import dev.vality.woody.thrift.impl.http.THSpawnClientBuilder;
|
import dev.vality.woody.thrift.impl.http.THSpawnClientBuilder;
|
||||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
|
||||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -71,11 +69,6 @@ public class ApplicationConfig {
|
|||||||
.build(FileStorageSrv.Iface.class);
|
.build(FileStorageSrv.Iface.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public CloseableHttpClient httpClient() {
|
|
||||||
return HttpClients.createDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ExecutorService disputesThreadPool(@Value("${dispute.batchSize}") int threadPoolSize) {
|
public ExecutorService disputesThreadPool(@Value("${dispute.batchSize}") int threadPoolSize) {
|
||||||
final var threadFactory = new ThreadFactoryBuilder()
|
final var threadFactory = new ThreadFactoryBuilder()
|
||||||
|
@ -11,11 +11,12 @@ import java.util.concurrent.Executor;
|
|||||||
@SuppressWarnings("AbbreviationAsWordInName")
|
@SuppressWarnings("AbbreviationAsWordInName")
|
||||||
public class AsyncMDCConfiguration {
|
public class AsyncMDCConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean("dominantAsyncServiceExecutor")
|
||||||
public Executor asyncExecutor() {
|
public Executor dominantAsyncServiceExecutor() {
|
||||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
var executor = new ThreadPoolTaskExecutor();
|
||||||
executor.setTaskDecorator(new MDCTaskDecorator());
|
executor.setTaskDecorator(new MDCTaskDecorator());
|
||||||
executor.initialize();
|
executor.initialize();
|
||||||
|
executor.setThreadNamePrefix("dominantAsyncService-thread-");
|
||||||
return executor;
|
return executor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package dev.vality.disputes.config;
|
||||||
|
|
||||||
|
import dev.vality.disputes.config.properties.HttpClientProperties;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.apache.hc.client5.http.config.ConnectionConfig;
|
||||||
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
|
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||||
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||||
|
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||||
|
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
||||||
|
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
|
||||||
|
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
||||||
|
import org.apache.hc.client5.http.ssl.TrustAllStrategy;
|
||||||
|
import org.apache.hc.core5.http.config.Registry;
|
||||||
|
import org.apache.hc.core5.http.config.RegistryBuilder;
|
||||||
|
import org.apache.hc.core5.ssl.SSLContextBuilder;
|
||||||
|
import org.apache.hc.core5.util.Timeout;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class HttpClientConfig {
|
||||||
|
|
||||||
|
private final HttpClientProperties httpClientProperties;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CloseableHttpClient httpClient(
|
||||||
|
PoolingHttpClientConnectionManager manager,
|
||||||
|
RequestConfig requestConfig) {
|
||||||
|
return HttpClients.custom()
|
||||||
|
.setConnectionManager(manager)
|
||||||
|
.setDefaultRequestConfig(requestConfig)
|
||||||
|
.disableAutomaticRetries()
|
||||||
|
.setConnectionManagerShared(true)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
|
||||||
|
var connectionManager = new PoolingHttpClientConnectionManager(connectionSocketFactory());
|
||||||
|
connectionManager.setMaxTotal(httpClientProperties.getMaxTotalPooling());
|
||||||
|
connectionManager.setDefaultMaxPerRoute(httpClientProperties.getDefaultMaxPerRoute());
|
||||||
|
connectionManager.setDefaultConnectionConfig(connectionConfig(httpClientProperties));
|
||||||
|
return connectionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RequestConfig requestConfig() {
|
||||||
|
return RequestConfig.custom()
|
||||||
|
.setConnectionRequestTimeout(Timeout.ofMilliseconds(httpClientProperties.getPoolTimeout()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private Registry<ConnectionSocketFactory> connectionSocketFactory() {
|
||||||
|
var sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustAllStrategy()).build();
|
||||||
|
var sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
|
||||||
|
return RegistryBuilder.<ConnectionSocketFactory>create()
|
||||||
|
.register("https", sslConnectionSocketFactory)
|
||||||
|
.register("http", new PlainConnectionSocketFactory())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConnectionConfig connectionConfig(HttpClientProperties httpClientProperties) {
|
||||||
|
return ConnectionConfig.custom()
|
||||||
|
.setConnectTimeout(Timeout.ofMilliseconds(httpClientProperties.getConnectionTimeout()))
|
||||||
|
.setSocketTimeout(Timeout.ofMilliseconds(httpClientProperties.getRequestTimeout()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package dev.vality.disputes.config.properties;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Validated
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties("http-client")
|
||||||
|
public class HttpClientProperties {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private int maxTotalPooling;
|
||||||
|
@NotNull
|
||||||
|
private int defaultMaxPerRoute;
|
||||||
|
@NotNull
|
||||||
|
private int requestTimeout;
|
||||||
|
@NotNull
|
||||||
|
private int poolTimeout;
|
||||||
|
@NotNull
|
||||||
|
private int connectionTimeout;
|
||||||
|
|
||||||
|
}
|
@ -62,15 +62,18 @@ public class DisputeDao extends AbstractGenericDao {
|
|||||||
.orElse(List.of());
|
.orElse(List.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dispute getForUpdateSkipLocked(long disputeId) {
|
public Optional<Dispute> get(long disputeId) {
|
||||||
|
var query = getDslContext().selectFrom(DISPUTE)
|
||||||
|
.where(DISPUTE.ID.eq(disputeId));
|
||||||
|
return Optional.ofNullable(fetchOne(query, disputeRowMapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Dispute> getForUpdateSkipLocked(long disputeId) {
|
||||||
var query = getDslContext().selectFrom(DISPUTE)
|
var query = getDslContext().selectFrom(DISPUTE)
|
||||||
.where(DISPUTE.ID.eq(disputeId))
|
.where(DISPUTE.ID.eq(disputeId))
|
||||||
.forUpdate()
|
.forUpdate()
|
||||||
.skipLocked();
|
.skipLocked();
|
||||||
return Optional.ofNullable(fetchOne(query, disputeRowMapper))
|
return Optional.ofNullable(fetchOne(query, disputeRowMapper));
|
||||||
.orElseThrow(
|
|
||||||
() -> new NotFoundException(
|
|
||||||
String.format("Dispute not found, disputeId='%s'", disputeId)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Dispute> getDisputesForUpdateSkipLocked(int limit, DisputeStatus disputeStatus) {
|
public List<Dispute> getDisputesForUpdateSkipLocked(int limit, DisputeStatus disputeStatus) {
|
||||||
|
@ -0,0 +1,128 @@
|
|||||||
|
package dev.vality.disputes.manualparsing;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
|
import dev.vality.disputes.admin.*;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping({"/debug/disputes-api/manual-parsing"})
|
||||||
|
@Slf4j
|
||||||
|
public class DebugManualParsingController {
|
||||||
|
|
||||||
|
private final ManualParsingServiceSrv.Iface manualParsingHandler;
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@PostMapping("/cancel")
|
||||||
|
@SneakyThrows
|
||||||
|
public void cancelPending(@RequestBody String body) {
|
||||||
|
log.debug("cancelPending {}", body);
|
||||||
|
manualParsingHandler.cancelPending(objectMapper.readValue(body, CancelParamsRequest.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/approve")
|
||||||
|
@SneakyThrows
|
||||||
|
public void approvePending(@RequestBody String body) {
|
||||||
|
log.debug("approvePending {}", body);
|
||||||
|
manualParsingHandler.approvePending(objectMapper.readValue(body, ApproveParamsRequest.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/bind")
|
||||||
|
@SneakyThrows
|
||||||
|
public void bindCreated(@RequestBody String body) {
|
||||||
|
log.debug("bindCreated {}", body);
|
||||||
|
manualParsingHandler.bindCreated(objectMapper.readValue(body, BindParamsRequest.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get")
|
||||||
|
@SneakyThrows
|
||||||
|
public DisputeResult getDisputes(@RequestBody String body) {
|
||||||
|
log.debug("getDispute {}", body);
|
||||||
|
var dispute = manualParsingHandler.getDispute(objectMapper.readValue(body, DisputeParamsRequest.class));
|
||||||
|
return objectMapper.convertValue(dispute, new TypeReference<>() {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static class DisputeResult {
|
||||||
|
|
||||||
|
@JsonProperty("disputes")
|
||||||
|
private List<Dispute> disputes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static class Dispute {
|
||||||
|
|
||||||
|
@JsonProperty("disputeId")
|
||||||
|
private String disputeId; // required
|
||||||
|
@JsonProperty("providerDisputeId")
|
||||||
|
private String providerDisputeId; // optional
|
||||||
|
@JsonProperty("invoiceId")
|
||||||
|
private String invoiceId; // required
|
||||||
|
@JsonProperty("paymentId")
|
||||||
|
private String paymentId; // required
|
||||||
|
@JsonProperty("providerTrxId")
|
||||||
|
private String providerTrxId; // required
|
||||||
|
@JsonProperty("status")
|
||||||
|
private String status; // required
|
||||||
|
@JsonProperty("errorMessage")
|
||||||
|
private String errorMessage; // optional
|
||||||
|
@JsonProperty("amount")
|
||||||
|
private String amount; // required
|
||||||
|
@JsonProperty("changedAmount")
|
||||||
|
private String changedAmount; // optional
|
||||||
|
@JsonProperty("skipCallHgForCreateAdjustment")
|
||||||
|
private boolean skipCallHgForCreateAdjustment; // required
|
||||||
|
@JsonProperty("attachments")
|
||||||
|
@JsonDeserialize(using = AttachmentDeserializer.class)
|
||||||
|
public List<Attachment> attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static class Attachment {
|
||||||
|
|
||||||
|
private String data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AttachmentDeserializer extends JsonDeserializer<Attachment> {
|
||||||
|
|
||||||
|
private final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Attachment deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
|
||||||
|
var node = (JsonNode) parser.getCodec().readTree(parser);
|
||||||
|
if (node.isObject()) {
|
||||||
|
var attachment = mapper.convertValue(node, new TypeReference<dev.vality.disputes.admin.Attachment>() {
|
||||||
|
});
|
||||||
|
var attachmentResult = new Attachment();
|
||||||
|
attachmentResult.setData(Base64.getEncoder().encodeToString(attachment.getData()));
|
||||||
|
return attachmentResult;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,30 @@
|
|||||||
package dev.vality.disputes.manualparsing;
|
package dev.vality.disputes.manualparsing;
|
||||||
|
|
||||||
import dev.vality.disputes.admin.ApproveParams;
|
import dev.vality.disputes.admin.*;
|
||||||
import dev.vality.disputes.admin.BindParams;
|
|
||||||
import dev.vality.disputes.admin.CancelParams;
|
|
||||||
import dev.vality.disputes.dao.DisputeDao;
|
import dev.vality.disputes.dao.DisputeDao;
|
||||||
|
import dev.vality.disputes.dao.FileMetaDao;
|
||||||
import dev.vality.disputes.dao.ProviderDisputeDao;
|
import dev.vality.disputes.dao.ProviderDisputeDao;
|
||||||
import dev.vality.disputes.domain.enums.DisputeStatus;
|
import dev.vality.disputes.domain.enums.DisputeStatus;
|
||||||
import dev.vality.disputes.domain.tables.pojos.ProviderDispute;
|
import dev.vality.disputes.domain.tables.pojos.ProviderDispute;
|
||||||
|
import dev.vality.disputes.service.external.FileStorageService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||||
|
import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler;
|
||||||
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
|
import org.apache.hc.core5.http.HttpEntity;
|
||||||
|
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Isolation;
|
import org.springframework.transaction.annotation.Isolation;
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static dev.vality.disputes.api.service.ApiDisputesService.DISPUTE_PENDING;
|
import static dev.vality.disputes.api.service.ApiDisputesService.DISPUTE_PENDING;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -24,13 +35,20 @@ public class ManualParsingDisputesService {
|
|||||||
|
|
||||||
private final DisputeDao disputeDao;
|
private final DisputeDao disputeDao;
|
||||||
private final ProviderDisputeDao providerDisputeDao;
|
private final ProviderDisputeDao providerDisputeDao;
|
||||||
|
private final FileMetaDao fileMetaDao;
|
||||||
|
private final FileStorageService fileStorageService;
|
||||||
|
private final CloseableHttpClient httpClient;
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
|
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
|
||||||
public void cancelPendingDispute(CancelParams cancelParams) {
|
public void cancelPendingDispute(CancelParams cancelParams) {
|
||||||
var disputeId = cancelParams.getDisputeId();
|
var disputeId = cancelParams.getDisputeId();
|
||||||
var cancelReason = cancelParams.getCancelReason().orElse(null);
|
|
||||||
log.debug("Trying to getForUpdateSkipLocked {}", disputeId);
|
log.debug("Trying to getForUpdateSkipLocked {}", disputeId);
|
||||||
var dispute = disputeDao.getForUpdateSkipLocked(Long.parseLong(disputeId));
|
var disputeOptional = disputeDao.getForUpdateSkipLocked(Long.parseLong(disputeId));
|
||||||
|
if (disputeOptional.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var cancelReason = cancelParams.getCancelReason().orElse(null);
|
||||||
|
var dispute = disputeOptional.get();
|
||||||
log.debug("GetForUpdateSkipLocked has been found {}", dispute);
|
log.debug("GetForUpdateSkipLocked has been found {}", dispute);
|
||||||
if (DISPUTE_PENDING.contains(dispute.getStatus())) {
|
if (DISPUTE_PENDING.contains(dispute.getStatus())) {
|
||||||
// используется не failed, а cancelled чтоб можно было понять, что зафейлен по внешнему вызову
|
// используется не failed, а cancelled чтоб можно было понять, что зафейлен по внешнему вызову
|
||||||
@ -46,7 +64,11 @@ public class ManualParsingDisputesService {
|
|||||||
public void approvePendingDispute(ApproveParams approveParam) {
|
public void approvePendingDispute(ApproveParams approveParam) {
|
||||||
var disputeId = approveParam.getDisputeId();
|
var disputeId = approveParam.getDisputeId();
|
||||||
log.debug("Trying to getForUpdateSkipLocked {}", disputeId);
|
log.debug("Trying to getForUpdateSkipLocked {}", disputeId);
|
||||||
var dispute = disputeDao.getForUpdateSkipLocked(Long.parseLong(disputeId));
|
var disputeOptional = disputeDao.getForUpdateSkipLocked(Long.parseLong(disputeId));
|
||||||
|
if (disputeOptional.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var dispute = disputeOptional.get();
|
||||||
log.debug("GetForUpdateSkipLocked has been found {}", dispute);
|
log.debug("GetForUpdateSkipLocked has been found {}", dispute);
|
||||||
var skipCallHg = approveParam.isSkipCallHgForCreateAdjustment();
|
var skipCallHg = approveParam.isSkipCallHgForCreateAdjustment();
|
||||||
var targetStatus = skipCallHg ? DisputeStatus.succeeded : DisputeStatus.create_adjustment;
|
var targetStatus = skipCallHg ? DisputeStatus.succeeded : DisputeStatus.create_adjustment;
|
||||||
@ -70,19 +92,73 @@ public class ManualParsingDisputesService {
|
|||||||
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
|
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
|
||||||
public void bindCreatedDispute(BindParams bindParam) {
|
public void bindCreatedDispute(BindParams bindParam) {
|
||||||
var disputeId = bindParam.getDisputeId();
|
var disputeId = bindParam.getDisputeId();
|
||||||
var providerDisputeId = bindParam.getProviderDisputeId();
|
|
||||||
log.debug("Trying to getForUpdateSkipLocked {}", disputeId);
|
log.debug("Trying to getForUpdateSkipLocked {}", disputeId);
|
||||||
var dispute = disputeDao.getForUpdateSkipLocked(Long.parseLong(disputeId));
|
var disputeOptional = disputeDao.getForUpdateSkipLocked(Long.parseLong(disputeId));
|
||||||
|
if (disputeOptional.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var providerDisputeId = bindParam.getProviderDisputeId();
|
||||||
|
var dispute = disputeOptional.get();
|
||||||
log.debug("GetForUpdateSkipLocked has been found {}", dispute);
|
log.debug("GetForUpdateSkipLocked has been found {}", dispute);
|
||||||
if (dispute.getStatus() == DisputeStatus.manual_created) {
|
if (dispute.getStatus() == DisputeStatus.manual_created) {
|
||||||
// обрабатываем здесь только вручную созданные диспуты, у остальных предполагается,
|
// обрабатываем здесь только вручную созданные диспуты, у остальных предполагается,
|
||||||
// что providerDisputeId будет сохранен после создания диспута по API провайдера
|
// что providerDisputeId будет сохранен после создания диспута по API провайдера
|
||||||
log.info("Trying to set manual_parsing_binded_pending Dispute status {}", dispute);
|
log.info("Trying to set manual_pending Dispute status {}", dispute);
|
||||||
providerDisputeDao.save(new ProviderDispute(providerDisputeId, dispute.getId()));
|
providerDisputeDao.save(new ProviderDispute(providerDisputeId, dispute.getId()));
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.manual_pending);
|
disputeDao.update(dispute.getId(), DisputeStatus.manual_pending);
|
||||||
log.debug("Dispute status has been set to manual_parsing_binded_pending {}", dispute);
|
log.debug("Dispute status has been set to manual_pending {}", dispute);
|
||||||
|
} else if (dispute.getStatus() == DisputeStatus.already_exist_created) {
|
||||||
|
log.info("Trying to set pending Dispute status {}", dispute);
|
||||||
|
providerDisputeDao.save(new ProviderDispute(providerDisputeId, dispute.getId()));
|
||||||
|
disputeDao.update(dispute.getId(), DisputeStatus.pending);
|
||||||
|
log.debug("Dispute status has been set to pending {}", dispute);
|
||||||
} else {
|
} else {
|
||||||
log.info("Request was skipped by inappropriate status {}", dispute);
|
log.info("Request was skipped by inappropriate status {}", dispute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public Dispute getDispute(DisputeParams disputeParams) {
|
||||||
|
var disputeId = disputeParams.getDisputeId();
|
||||||
|
var disputeOptional = disputeDao.get(Long.parseLong(disputeId));
|
||||||
|
if (disputeOptional.isEmpty()) {
|
||||||
|
log.debug("Trying to get Dispute but null {}", disputeId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var dispute = disputeOptional.get();
|
||||||
|
var disputeResult = new Dispute();
|
||||||
|
disputeResult.setDisputeId(disputeId);
|
||||||
|
disputeResult.setProviderDisputeId(Optional.ofNullable(providerDisputeDao.get(dispute.getId()))
|
||||||
|
.map(ProviderDispute::getProviderDisputeId)
|
||||||
|
.orElse(null));
|
||||||
|
disputeResult.setInvoiceId(dispute.getInvoiceId());
|
||||||
|
disputeResult.setPaymentId(dispute.getPaymentId());
|
||||||
|
disputeResult.setProviderTrxId(dispute.getProviderTrxId());
|
||||||
|
disputeResult.setStatus(dispute.getStatus().name());
|
||||||
|
disputeResult.setErrorMessage(dispute.getErrorMessage());
|
||||||
|
disputeResult.setAmount(String.valueOf(dispute.getAmount()));
|
||||||
|
disputeResult.setChangedAmount(Optional.ofNullable(dispute.getChangedAmount())
|
||||||
|
.map(String::valueOf)
|
||||||
|
.orElse(null));
|
||||||
|
disputeResult.setSkipCallHgForCreateAdjustment(dispute.getSkipCallHgForCreateAdjustment());
|
||||||
|
log.debug("Dispute getDispute {}", disputeResult);
|
||||||
|
var disputeFiles = fileMetaDao.getDisputeFiles(dispute.getId());
|
||||||
|
if (disputeFiles == null) {
|
||||||
|
return disputeResult;
|
||||||
|
}
|
||||||
|
disputeResult.setAttachments(new ArrayList<>());
|
||||||
|
for (var disputeFile : disputeFiles) {
|
||||||
|
var downloadUrl = fileStorageService.generateDownloadUrl(disputeFile.getFileId());
|
||||||
|
var data = httpClient.execute(
|
||||||
|
new HttpGet(downloadUrl),
|
||||||
|
new AbstractHttpClientResponseHandler<byte[]>() {
|
||||||
|
@Override
|
||||||
|
public byte[] handleEntity(HttpEntity entity) throws IOException {
|
||||||
|
return EntityUtils.toByteArray(entity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
disputeResult.getAttachments().get().add(new Attachment(ByteBuffer.wrap(data)));
|
||||||
|
}
|
||||||
|
return disputeResult;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.apache.thrift.TException;
|
import org.apache.thrift.TException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -30,8 +32,20 @@ public class ManualParsingHandler implements ManualParsingServiceSrv.Iface {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bindCreated(BindParamsRequest bindParamsRequest) throws TException {
|
public void bindCreated(BindParamsRequest bindParamsRequest) throws TException {
|
||||||
for (BindParams bindParam : bindParamsRequest.getBindParams()) {
|
for (var bindParam : bindParamsRequest.getBindParams()) {
|
||||||
manualParsingDisputesService.bindCreatedDispute(bindParam);
|
manualParsingDisputesService.bindCreatedDispute(bindParam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisputeResult getDispute(DisputeParamsRequest disputeParamsRequest) throws TException {
|
||||||
|
var disputeResult = new DisputeResult(new ArrayList<>());
|
||||||
|
for (var disputeParams : disputeParamsRequest.getDisputeParams()) {
|
||||||
|
var dispute = manualParsingDisputesService.getDispute(disputeParams);
|
||||||
|
if (dispute != null) {
|
||||||
|
disputeResult.getDisputes().add(dispute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return disputeResult;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.slf4j.MDC;
|
import org.slf4j.MDC;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -23,8 +21,7 @@ public class ManualParsingTopic {
|
|||||||
@Value("${manual-parsing-topic.enabled}")
|
@Value("${manual-parsing-topic.enabled}")
|
||||||
private boolean enabled;
|
private boolean enabled;
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
public void sendCreated(Dispute dispute, List<Attachment> attachments, DisputeStatus disputeStatus) {
|
||||||
public void sendCreated(Dispute dispute, List<Attachment> attachments) {
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -32,7 +29,7 @@ public class ManualParsingTopic {
|
|||||||
contextMap.put("dispute_id", dispute.getId().toString());
|
contextMap.put("dispute_id", dispute.getId().toString());
|
||||||
var attachmentsCollect = attachments.stream().map(Attachment::toString).collect(Collectors.joining(", "));
|
var attachmentsCollect = attachments.stream().map(Attachment::toString).collect(Collectors.joining(", "));
|
||||||
contextMap.put("dispute_attachments", attachmentsCollect);
|
contextMap.put("dispute_attachments", attachmentsCollect);
|
||||||
contextMap.put("dispute_status", DisputeStatus.manual_created.name());
|
contextMap.put("dispute_status", disputeStatus.name());
|
||||||
MDC.setContextMap(contextMap);
|
MDC.setContextMap(contextMap);
|
||||||
log.warn("Manual parsing case");
|
log.warn("Manual parsing case");
|
||||||
MDC.clear();
|
MDC.clear();
|
||||||
|
@ -6,16 +6,12 @@ import dev.vality.damsel.domain.Terminal;
|
|||||||
import dev.vality.damsel.domain.TerminalRef;
|
import dev.vality.damsel.domain.TerminalRef;
|
||||||
import dev.vality.disputes.domain.tables.pojos.Dispute;
|
import dev.vality.disputes.domain.tables.pojos.Dispute;
|
||||||
import dev.vality.disputes.service.external.DominantService;
|
import dev.vality.disputes.service.external.DominantService;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ExponentialBackOffPollingServiceWrapper {
|
public class ExponentialBackOffPollingServiceWrapper {
|
||||||
@ -33,20 +29,17 @@ public class ExponentialBackOffPollingServiceWrapper {
|
|||||||
return getLocalDateTime(pollingInfo.getStartDateTimePolling().plusSeconds(seconds));
|
return getLocalDateTime(pollingInfo.getStartDateTimePolling().plusSeconds(seconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
|
||||||
@SneakyThrows
|
|
||||||
public LocalDateTime prepareNextPollingInterval(Dispute dispute) {
|
public LocalDateTime prepareNextPollingInterval(Dispute dispute) {
|
||||||
var pollingInfo = new PollingInfo();
|
var pollingInfo = new PollingInfo();
|
||||||
var startDateTimePolling = dispute.getCreatedAt().toInstant(ZoneOffset.UTC);
|
var startDateTimePolling = dispute.getCreatedAt().toInstant(ZoneOffset.UTC);
|
||||||
pollingInfo.setStartDateTimePolling(startDateTimePolling);
|
pollingInfo.setStartDateTimePolling(startDateTimePolling);
|
||||||
pollingInfo.setMaxDateTimePolling(dispute.getPollingBefore().toInstant(ZoneOffset.UTC));
|
pollingInfo.setMaxDateTimePolling(dispute.getPollingBefore().toInstant(ZoneOffset.UTC));
|
||||||
var terminal = getTerminal(dispute.getTerminalId());
|
var terminal = getTerminal(dispute.getTerminalId());
|
||||||
var seconds = exponentialBackOffPollingService.prepareNextPollingInterval(
|
var seconds = exponentialBackOffPollingService.prepareNextPollingInterval(pollingInfo, terminal.getOptions());
|
||||||
pollingInfo, terminal.get().getOptions());
|
|
||||||
return getLocalDateTime(startDateTimePolling.plusSeconds(seconds));
|
return getLocalDateTime(startDateTimePolling.plusSeconds(seconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Terminal> getTerminal(Integer terminalId) {
|
private Terminal getTerminal(Integer terminalId) {
|
||||||
return dominantService.getTerminal(new TerminalRef(terminalId));
|
return dominantService.getTerminal(new TerminalRef(terminalId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import java.util.stream.Collectors;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@SuppressWarnings({"ParameterName", "LineLength", "MissingSwitchDefault"})
|
||||||
public class TaskCreateAdjustmentsService {
|
public class TaskCreateAdjustmentsService {
|
||||||
|
|
||||||
private final ExecutorService disputesThreadPool;
|
private final ExecutorService disputesThreadPool;
|
||||||
@ -25,12 +26,12 @@ public class TaskCreateAdjustmentsService {
|
|||||||
@Value("${dispute.isScheduleCreateAdjustmentsEnabled}")
|
@Value("${dispute.isScheduleCreateAdjustmentsEnabled}")
|
||||||
private boolean isScheduleCreateAdjustmentsEnabled;
|
private boolean isScheduleCreateAdjustmentsEnabled;
|
||||||
|
|
||||||
@Scheduled(fixedDelayString = "${dispute.fixedDelayCreateAdjustments}")
|
@Scheduled(fixedDelayString = "${dispute.fixedDelayCreateAdjustments}", initialDelayString = "${dispute.initialDelayCreateAdjustments}")
|
||||||
public void processPending() {
|
public void processPending() {
|
||||||
if (!isScheduleCreateAdjustmentsEnabled) {
|
if (!isScheduleCreateAdjustmentsEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.info("Processing create adjustments get started");
|
log.debug("Processing create adjustments get started");
|
||||||
try {
|
try {
|
||||||
var disputes = createAdjustmentsService.getDisputesForHgCall(batchSize);
|
var disputes = createAdjustmentsService.getDisputesForHgCall(batchSize);
|
||||||
var callables = disputes.stream()
|
var callables = disputes.stream()
|
||||||
@ -40,7 +41,7 @@ public class TaskCreateAdjustmentsService {
|
|||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
log.error("Received InterruptedException while thread executed report", ex);
|
log.error("Received InterruptedException while thread executed report", ex);
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} catch (Exception ex) {
|
} catch (Throwable ex) {
|
||||||
log.error("Received exception while scheduler processed create adjustments", ex);
|
log.error("Received exception while scheduler processed create adjustments", ex);
|
||||||
}
|
}
|
||||||
log.info("Create adjustments were processed");
|
log.info("Create adjustments were processed");
|
||||||
|
@ -25,12 +25,12 @@ public class TaskCreatedDisputesService {
|
|||||||
@Value("${dispute.isScheduleCreatedEnabled}")
|
@Value("${dispute.isScheduleCreatedEnabled}")
|
||||||
private boolean isScheduleCreatedEnabled;
|
private boolean isScheduleCreatedEnabled;
|
||||||
|
|
||||||
@Scheduled(fixedDelayString = "${dispute.fixedDelayCreated}")
|
@Scheduled(fixedDelayString = "${dispute.fixedDelayCreated}", initialDelayString = "${dispute.initialDelayCreated}")
|
||||||
public void processCreated() {
|
public void processCreated() {
|
||||||
if (!isScheduleCreatedEnabled) {
|
if (!isScheduleCreatedEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.info("Processing created disputes get started");
|
log.debug("Processing created disputes get started");
|
||||||
try {
|
try {
|
||||||
var disputes = createdDisputesService.getCreatedDisputesForUpdateSkipLocked(batchSize);
|
var disputes = createdDisputesService.getCreatedDisputesForUpdateSkipLocked(batchSize);
|
||||||
var callables = disputes.stream()
|
var callables = disputes.stream()
|
||||||
@ -40,7 +40,7 @@ public class TaskCreatedDisputesService {
|
|||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
log.error("Received InterruptedException while thread executed report", ex);
|
log.error("Received InterruptedException while thread executed report", ex);
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} catch (Exception ex) {
|
} catch (Throwable ex) {
|
||||||
log.error("Received exception while scheduler processed created disputes", ex);
|
log.error("Received exception while scheduler processed created disputes", ex);
|
||||||
}
|
}
|
||||||
log.info("Created disputes were processed");
|
log.info("Created disputes were processed");
|
||||||
|
@ -25,12 +25,12 @@ public class TaskPendingDisputesService {
|
|||||||
@Value("${dispute.isSchedulePendingEnabled}")
|
@Value("${dispute.isSchedulePendingEnabled}")
|
||||||
private boolean isSchedulePendingEnabled;
|
private boolean isSchedulePendingEnabled;
|
||||||
|
|
||||||
@Scheduled(fixedDelayString = "${dispute.fixedDelayPending}")
|
@Scheduled(fixedDelayString = "${dispute.fixedDelayPending}", initialDelayString = "${dispute.initialDelayPending}")
|
||||||
public void processPending() {
|
public void processPending() {
|
||||||
if (!isSchedulePendingEnabled) {
|
if (!isSchedulePendingEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.info("Processing pending disputes get started");
|
log.debug("Processing pending disputes get started");
|
||||||
try {
|
try {
|
||||||
var disputes = pendingDisputesService.getPendingDisputesForUpdateSkipLocked(batchSize);
|
var disputes = pendingDisputesService.getPendingDisputesForUpdateSkipLocked(batchSize);
|
||||||
var callables = disputes.stream()
|
var callables = disputes.stream()
|
||||||
@ -40,7 +40,7 @@ public class TaskPendingDisputesService {
|
|||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
log.error("Received InterruptedException while thread executed report", ex);
|
log.error("Received InterruptedException while thread executed report", ex);
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} catch (Exception ex) {
|
} catch (Throwable ex) {
|
||||||
log.error("Received exception while scheduler processed pending disputes", ex);
|
log.error("Received exception while scheduler processed pending disputes", ex);
|
||||||
}
|
}
|
||||||
log.info("Pending disputes were processed");
|
log.info("Pending disputes were processed");
|
||||||
|
@ -17,11 +17,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ -34,37 +31,42 @@ public class RemoteClient {
|
|||||||
private final DisputeContextConverter disputeContextConverter;
|
private final DisputeContextConverter disputeContextConverter;
|
||||||
private final DisputeParamsConverter disputeParamsConverter;
|
private final DisputeParamsConverter disputeParamsConverter;
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public DisputeCreatedResult createDispute(Dispute dispute, List<Attachment> attachments) {
|
public DisputeCreatedResult createDispute(Dispute dispute, List<Attachment> attachments) {
|
||||||
|
log.debug("Trying to call dominant for RemoteClient {}", dispute.getId());
|
||||||
var terminal = getTerminal(dispute.getTerminalId());
|
var terminal = getTerminal(dispute.getTerminalId());
|
||||||
var proxy = getProxy(dispute.getProviderId());
|
var proxy = getProxy(dispute.getProviderId());
|
||||||
var disputeParams = disputeParamsConverter.convert(dispute, attachments, terminal.get().getOptions());
|
log.debug("Trying to build disputeParams {}", dispute.getId());
|
||||||
var remoteClient = providerIfaceBuilder.build(terminal.get().getOptions(), proxy.get().getUrl());
|
var disputeParams = disputeParamsConverter.convert(dispute, attachments, terminal.getOptions());
|
||||||
log.info("Trying to routed remote provider's createDispute() call {}", dispute);
|
log.debug("Trying to call ProviderIfaceBuilder {}", dispute.getId());
|
||||||
|
var remoteClient = providerIfaceBuilder.buildTHSpawnClient(terminal.getOptions(), proxy.getUrl());
|
||||||
|
log.debug("Trying to routed remote provider's createDispute() call {}", dispute.getId());
|
||||||
var result = remoteClient.createDispute(disputeParams);
|
var result = remoteClient.createDispute(disputeParams);
|
||||||
log.debug("Routed remote provider's createDispute() has been called {}", dispute);
|
log.info("Routed remote provider's createDispute() has been called {} {}", dispute.getId(), result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public DisputeStatusResult checkDisputeStatus(Dispute dispute, ProviderDispute providerDispute) {
|
public DisputeStatusResult checkDisputeStatus(Dispute dispute, ProviderDispute providerDispute) {
|
||||||
|
log.debug("Trying to call dominant for RemoteClient {}", dispute.getId());
|
||||||
var terminal = getTerminal(dispute.getTerminalId());
|
var terminal = getTerminal(dispute.getTerminalId());
|
||||||
var proxy = getProxy(dispute.getProviderId());
|
var proxy = getProxy(dispute.getProviderId());
|
||||||
var disputeContext = disputeContextConverter.convert(dispute, providerDispute, terminal.get().getOptions());
|
log.debug("Trying to build disputeContext {}", dispute.getId());
|
||||||
var remoteClient = providerIfaceBuilder.build(terminal.get().getOptions(), proxy.get().getUrl());
|
var disputeContext = disputeContextConverter.convert(dispute, providerDispute, terminal.getOptions());
|
||||||
log.info("Trying to routed remote provider's checkDisputeStatus() call {}", dispute);
|
log.debug("Trying to call ProviderIfaceBuilder {}", dispute.getId());
|
||||||
|
var remoteClient = providerIfaceBuilder.buildTHSpawnClient(terminal.getOptions(), proxy.getUrl());
|
||||||
|
log.debug("Trying to routed remote provider's checkDisputeStatus() call {}", dispute.getId());
|
||||||
var result = remoteClient.checkDisputeStatus(disputeContext);
|
var result = remoteClient.checkDisputeStatus(disputeContext);
|
||||||
log.debug("Routed remote provider's checkDisputeStatus() has been called {}", dispute);
|
log.info("Routed remote provider's checkDisputeStatus() has been called {} {}", dispute.getId(), result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<ProxyDefinition> getProxy(Integer providerId) {
|
private ProxyDefinition getProxy(Integer providerId) {
|
||||||
return dominantService.getProxy(new ProviderRef(providerId));
|
var provider = dominantService.getProvider(new ProviderRef(providerId));
|
||||||
|
return dominantService.getProxy(provider.getProxy().getRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Terminal> getTerminal(Integer terminalId) {
|
private Terminal getTerminal(Integer terminalId) {
|
||||||
return dominantService.getTerminal(new TerminalRef(terminalId));
|
return dominantService.getTerminal(new TerminalRef(terminalId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,10 @@ package dev.vality.disputes.schedule.handler;
|
|||||||
import dev.vality.disputes.domain.tables.pojos.Dispute;
|
import dev.vality.disputes.domain.tables.pojos.Dispute;
|
||||||
import dev.vality.disputes.schedule.service.CreateAdjustmentsService;
|
import dev.vality.disputes.schedule.service.CreateAdjustmentsService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class CreateAdjustmentHandler {
|
public class CreateAdjustmentHandler {
|
||||||
|
|
||||||
private final CreateAdjustmentsService createAdjustmentsService;
|
private final CreateAdjustmentsService createAdjustmentsService;
|
||||||
@ -12,10 +14,13 @@ public class CreateAdjustmentHandler {
|
|||||||
public Long handle(Dispute dispute) {
|
public Long handle(Dispute dispute) {
|
||||||
final var currentThread = Thread.currentThread();
|
final var currentThread = Thread.currentThread();
|
||||||
final var oldName = currentThread.getName();
|
final var oldName = currentThread.getName();
|
||||||
currentThread.setName("dispute-create-adjustment-" + dispute.getId());
|
currentThread.setName("dispute-created-adjustment-id-" + dispute.getId() + "-" + oldName);
|
||||||
try {
|
try {
|
||||||
createAdjustmentsService.callHgForCreateAdjustment(dispute);
|
createAdjustmentsService.callHgForCreateAdjustment(dispute);
|
||||||
return dispute.getId();
|
return dispute.getId();
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
log.error("Received exception while scheduler processed callHgForCreateAdjustment", ex);
|
||||||
|
throw ex;
|
||||||
} finally {
|
} finally {
|
||||||
currentThread.setName(oldName);
|
currentThread.setName(oldName);
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,10 @@ package dev.vality.disputes.schedule.handler;
|
|||||||
import dev.vality.disputes.domain.tables.pojos.Dispute;
|
import dev.vality.disputes.domain.tables.pojos.Dispute;
|
||||||
import dev.vality.disputes.schedule.service.CreatedDisputesService;
|
import dev.vality.disputes.schedule.service.CreatedDisputesService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class CreatedDisputeHandler {
|
public class CreatedDisputeHandler {
|
||||||
|
|
||||||
private final CreatedDisputesService createdDisputesService;
|
private final CreatedDisputesService createdDisputesService;
|
||||||
@ -12,10 +14,13 @@ public class CreatedDisputeHandler {
|
|||||||
public Long handle(Dispute dispute) {
|
public Long handle(Dispute dispute) {
|
||||||
final var currentThread = Thread.currentThread();
|
final var currentThread = Thread.currentThread();
|
||||||
final var oldName = currentThread.getName();
|
final var oldName = currentThread.getName();
|
||||||
currentThread.setName("dispute-created-" + dispute.getId());
|
currentThread.setName("dispute-created-id-" + dispute.getId() + "-" + oldName);
|
||||||
try {
|
try {
|
||||||
createdDisputesService.callCreateDisputeRemotely(dispute);
|
createdDisputesService.callCreateDisputeRemotely(dispute);
|
||||||
return dispute.getId();
|
return dispute.getId();
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
log.error("Received exception while scheduler processed callCreateDisputeRemotely", ex);
|
||||||
|
throw ex;
|
||||||
} finally {
|
} finally {
|
||||||
currentThread.setName(oldName);
|
currentThread.setName(oldName);
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,10 @@ package dev.vality.disputes.schedule.handler;
|
|||||||
import dev.vality.disputes.domain.tables.pojos.Dispute;
|
import dev.vality.disputes.domain.tables.pojos.Dispute;
|
||||||
import dev.vality.disputes.schedule.service.PendingDisputesService;
|
import dev.vality.disputes.schedule.service.PendingDisputesService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class PendingDisputeHandler {
|
public class PendingDisputeHandler {
|
||||||
|
|
||||||
private final PendingDisputesService pendingDisputesService;
|
private final PendingDisputesService pendingDisputesService;
|
||||||
@ -12,10 +14,13 @@ public class PendingDisputeHandler {
|
|||||||
public Long handle(Dispute dispute) {
|
public Long handle(Dispute dispute) {
|
||||||
final var currentThread = Thread.currentThread();
|
final var currentThread = Thread.currentThread();
|
||||||
final var oldName = currentThread.getName();
|
final var oldName = currentThread.getName();
|
||||||
currentThread.setName("dispute-pending-" + dispute.getId());
|
currentThread.setName("dispute-pending-id-" + dispute.getId() + "-" + oldName);
|
||||||
try {
|
try {
|
||||||
pendingDisputesService.callPendingDisputeRemotely(dispute);
|
pendingDisputesService.callPendingDisputeRemotely(dispute);
|
||||||
return dispute.getId();
|
return dispute.getId();
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
log.error("Received exception while scheduler processed callPendingDisputeRemotely", ex);
|
||||||
|
throw ex;
|
||||||
} finally {
|
} finally {
|
||||||
currentThread.setName(oldName);
|
currentThread.setName(oldName);
|
||||||
}
|
}
|
||||||
|
@ -49,9 +49,9 @@ public class CreateAdjustmentsService {
|
|||||||
log.debug("GetDisputeForUpdateSkipLocked has been found {}", dispute);
|
log.debug("GetDisputeForUpdateSkipLocked has been found {}", dispute);
|
||||||
var invoicePayment = getInvoicePayment(dispute);
|
var invoicePayment = getInvoicePayment(dispute);
|
||||||
if (invoicePayment == null || !invoicePayment.isSetRoute()) {
|
if (invoicePayment == null || !invoicePayment.isSetRoute()) {
|
||||||
log.error("Trying to set failed Dispute status with PAYMENT_NOT_FOUND error reason {}", dispute);
|
log.error("Trying to set failed Dispute status with PAYMENT_NOT_FOUND error reason {}", dispute.getId());
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.failed, ErrorReason.PAYMENT_NOT_FOUND);
|
disputeDao.update(dispute.getId(), DisputeStatus.failed, ErrorReason.PAYMENT_NOT_FOUND);
|
||||||
log.debug("Dispute status has been set to failed {}", dispute);
|
log.debug("Dispute status has been set to failed {}", dispute.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var invoicePaymentAdjustment = adjustmentExtractor.searchAdjustmentByDispute(invoicePayment, dispute);
|
var invoicePaymentAdjustment = adjustmentExtractor.searchAdjustmentByDispute(invoicePayment, dispute);
|
||||||
@ -59,16 +59,16 @@ public class CreateAdjustmentsService {
|
|||||||
var changedAmount = adjustmentExtractor.getChangedAmount(invoicePaymentAdjustment.get(), dispute.getChangedAmount());
|
var changedAmount = adjustmentExtractor.getChangedAmount(invoicePaymentAdjustment.get(), dispute.getChangedAmount());
|
||||||
log.info("Trying to set succeeded Dispute status {}", dispute);
|
log.info("Trying to set succeeded Dispute status {}", dispute);
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.succeeded, changedAmount);
|
disputeDao.update(dispute.getId(), DisputeStatus.succeeded, changedAmount);
|
||||||
log.debug("Dispute status has been set to succeeded {}", dispute);
|
log.debug("Dispute status has been set to succeeded {}", dispute.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
var params = invoicePaymentAdjustmentParamsConverter.convert(dispute);
|
var params = invoicePaymentAdjustmentParamsConverter.convert(dispute);
|
||||||
var paymentAdjustment = createAdjustment(dispute, params);
|
var paymentAdjustment = createAdjustment(dispute, params);
|
||||||
if (paymentAdjustment == null) {
|
if (paymentAdjustment == null) {
|
||||||
log.error("Trying to set failed Dispute status with INVOICE_NOT_FOUND error reason {}", dispute);
|
log.error("Trying to set failed Dispute status with INVOICE_NOT_FOUND error reason {}", dispute.getId());
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.failed, ErrorReason.INVOICE_NOT_FOUND);
|
disputeDao.update(dispute.getId(), DisputeStatus.failed, ErrorReason.INVOICE_NOT_FOUND);
|
||||||
log.debug("Dispute status has been set to failed {}", dispute);
|
log.debug("Dispute status has been set to failed {}", dispute.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (InvoicingPaymentStatusPendingException e) {
|
} catch (InvoicingPaymentStatusPendingException e) {
|
||||||
@ -77,12 +77,12 @@ public class CreateAdjustmentsService {
|
|||||||
// и тогда диспут будет пулиться, пока платеж не зафиналится,
|
// и тогда диспут будет пулиться, пока платеж не зафиналится,
|
||||||
// и тк никакой записи в коде выше нет, то пуллинг не проблема
|
// и тк никакой записи в коде выше нет, то пуллинг не проблема
|
||||||
// а запрос в checkDisputeStatus по идемпотентности просто вернет тот же success
|
// а запрос в checkDisputeStatus по идемпотентности просто вернет тот же success
|
||||||
log.error("Error when hg.createPaymentAdjustment() got payments status pending {}", dispute, e);
|
log.error("Error when hg.createPaymentAdjustment() got payments status pending {}", dispute.getId(), e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.info("Trying to set succeeded Dispute status {}", dispute);
|
log.info("Trying to set succeeded Dispute status {}", dispute);
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.succeeded);
|
disputeDao.update(dispute.getId(), DisputeStatus.succeeded);
|
||||||
log.debug("Dispute status has been set to succeeded {}", dispute);
|
log.debug("Dispute status has been set to succeeded {}", dispute.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private InvoicePaymentAdjustment createAdjustment(Dispute dispute, InvoicePaymentAdjustmentParams params) {
|
private InvoicePaymentAdjustment createAdjustment(Dispute dispute, InvoicePaymentAdjustmentParams params) {
|
||||||
|
@ -9,8 +9,6 @@ import dev.vality.disputes.service.external.FileStorageService;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -23,7 +21,6 @@ public class CreatedAttachmentsService {
|
|||||||
private final FileMetaDao fileMetaDao;
|
private final FileMetaDao fileMetaDao;
|
||||||
private final FileStorageService fileStorageService;
|
private final FileStorageService fileStorageService;
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
|
||||||
public List<Attachment> getAttachments(Dispute dispute) {
|
public List<Attachment> getAttachments(Dispute dispute) {
|
||||||
log.debug("Trying to get Attachments {}", dispute);
|
log.debug("Trying to get Attachments {}", dispute);
|
||||||
try {
|
try {
|
||||||
|
@ -19,7 +19,6 @@ import dev.vality.disputes.service.external.InvoicingService;
|
|||||||
import dev.vality.geck.serializer.kit.tbase.TErrorUtil;
|
import dev.vality.geck.serializer.kit.tbase.TErrorUtil;
|
||||||
import dev.vality.woody.api.flow.error.WRuntimeException;
|
import dev.vality.woody.api.flow.error.WRuntimeException;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Isolation;
|
import org.springframework.transaction.annotation.Isolation;
|
||||||
@ -27,7 +26,6 @@ import org.springframework.transaction.annotation.Propagation;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
import static dev.vality.disputes.constant.TerminalOptionsField.DISPUTE_FLOW_CAPTURED_BLOCKED;
|
import static dev.vality.disputes.constant.TerminalOptionsField.DISPUTE_FLOW_CAPTURED_BLOCKED;
|
||||||
import static dev.vality.disputes.constant.TerminalOptionsField.DISPUTE_FLOW_PROVIDERS_API_EXIST;
|
import static dev.vality.disputes.constant.TerminalOptionsField.DISPUTE_FLOW_PROVIDERS_API_EXIST;
|
||||||
@ -57,7 +55,6 @@ public class CreatedDisputesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
|
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
|
||||||
@SneakyThrows
|
|
||||||
public void callCreateDisputeRemotely(Dispute dispute) {
|
public void callCreateDisputeRemotely(Dispute dispute) {
|
||||||
log.debug("Trying to getDisputeForUpdateSkipLocked {}", dispute);
|
log.debug("Trying to getDisputeForUpdateSkipLocked {}", dispute);
|
||||||
var forUpdate = disputeDao.getDisputeForUpdateSkipLocked(dispute.getId());
|
var forUpdate = disputeDao.getDisputeForUpdateSkipLocked(dispute.getId());
|
||||||
@ -68,39 +65,39 @@ public class CreatedDisputesService {
|
|||||||
log.debug("GetDisputeForUpdateSkipLocked has been found {}", dispute);
|
log.debug("GetDisputeForUpdateSkipLocked has been found {}", dispute);
|
||||||
var invoicePayment = getInvoicePayment(dispute);
|
var invoicePayment = getInvoicePayment(dispute);
|
||||||
if (invoicePayment == null || !invoicePayment.isSetRoute()) {
|
if (invoicePayment == null || !invoicePayment.isSetRoute()) {
|
||||||
log.error("Trying to set failed Dispute status with PAYMENT_NOT_FOUND error reason {}", dispute);
|
log.error("Trying to set failed Dispute status with PAYMENT_NOT_FOUND error reason {}", dispute.getId());
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.failed, ErrorReason.PAYMENT_NOT_FOUND);
|
disputeDao.update(dispute.getId(), DisputeStatus.failed, ErrorReason.PAYMENT_NOT_FOUND);
|
||||||
log.debug("Dispute status has been set to failed {}", dispute);
|
log.debug("Dispute status has been set to failed {}", dispute.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var status = invoicePayment.getPayment().getStatus();
|
var status = invoicePayment.getPayment().getStatus();
|
||||||
if (!status.isSetCaptured() && !status.isSetCancelled() && !status.isSetFailed()) {
|
if (!status.isSetCaptured() && !status.isSetCancelled() && !status.isSetFailed()) {
|
||||||
// не создаем диспут, пока платеж не финален
|
// не создаем диспут, пока платеж не финален
|
||||||
log.warn("Payment has non-final status {} {}", status, dispute);
|
log.warn("Payment has non-final status {} {}", status, dispute.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var attachments = createdAttachmentsService.getAttachments(dispute);
|
var attachments = createdAttachmentsService.getAttachments(dispute);
|
||||||
if (attachments == null || attachments.isEmpty()) {
|
if (attachments == null || attachments.isEmpty()) {
|
||||||
log.error("Trying to set failed Dispute status with NO_ATTACHMENTS error reason {}", dispute);
|
log.error("Trying to set failed Dispute status with NO_ATTACHMENTS error reason {}", dispute.getId());
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.failed, ErrorReason.NO_ATTACHMENTS);
|
disputeDao.update(dispute.getId(), DisputeStatus.failed, ErrorReason.NO_ATTACHMENTS);
|
||||||
log.debug("Dispute status has been set to failed {}", dispute);
|
log.debug("Dispute status has been set to failed {}", dispute.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((status.isSetCaptured() && isCapturedBlockedForDispute(dispute))
|
if ((status.isSetCaptured() && isCapturedBlockedForDispute(dispute))
|
||||||
|| isNotProvidersDisputesApiExist(dispute)) {
|
|| isNotProvidersDisputesApiExist(dispute)) {
|
||||||
// отправлять на ручной разбор, если выставлена опция
|
// отправлять на ручной разбор, если выставлена опция
|
||||||
// DISPUTE_FLOW_CAPTURED_BLOCKED или не выставлена DISPUTE_FLOW_PROVIDERS_API_EXIST
|
// DISPUTE_FLOW_CAPTURED_BLOCKED или не выставлена DISPUTE_FLOW_PROVIDERS_API_EXIST
|
||||||
finishTaskWithManualParsingFlowActivation(dispute, attachments);
|
finishTaskWithManualParsingFlowActivation(dispute, attachments, DisputeStatus.manual_created);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
var result = remoteClient.createDispute(dispute, attachments);
|
var result = remoteClient.createDispute(dispute, attachments);
|
||||||
finishTask(dispute, result);
|
finishTask(dispute, attachments, result);
|
||||||
} catch (WRuntimeException e) {
|
} catch (WRuntimeException e) {
|
||||||
if (externalGatewayChecker.isNotProvidersDisputesApiExist(dispute, e)) {
|
if (externalGatewayChecker.isNotProvidersDisputesApiExist(dispute, e)) {
|
||||||
// отправлять на ручной разбор, если API диспутов на провайдере не реализовано
|
// отправлять на ручной разбор, если API диспутов на провайдере не реализовано
|
||||||
// (тогда при тесте соединения вернется 404)
|
// (тогда при тесте соединения вернется 404)
|
||||||
finishTaskWithManualParsingFlowActivation(dispute, attachments);
|
finishTaskWithManualParsingFlowActivation(dispute, attachments, DisputeStatus.manual_created);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
@ -108,41 +105,41 @@ public class CreatedDisputesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
@Transactional(propagation = Propagation.REQUIRED)
|
||||||
void finishTask(Dispute dispute, DisputeCreatedResult result) {
|
void finishTask(Dispute dispute, List<Attachment> attachments, DisputeCreatedResult result) {
|
||||||
switch (result.getSetField()) {
|
switch (result.getSetField()) {
|
||||||
case SUCCESS_RESULT -> {
|
case SUCCESS_RESULT -> {
|
||||||
var nextCheckAfter = exponentialBackOffPollingService.prepareNextPollingInterval(dispute);
|
var nextCheckAfter = exponentialBackOffPollingService.prepareNextPollingInterval(dispute);
|
||||||
log.info("Trying to set pending Dispute status {}, {}", dispute, result);
|
log.info("Trying to set pending Dispute status {}, {}", dispute, result);
|
||||||
providerDisputeDao.save(new ProviderDispute(result.getSuccessResult().getProviderDisputeId(), dispute.getId()));
|
providerDisputeDao.save(new ProviderDispute(result.getSuccessResult().getProviderDisputeId(), dispute.getId()));
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.pending, nextCheckAfter);
|
disputeDao.update(dispute.getId(), DisputeStatus.pending, nextCheckAfter);
|
||||||
log.debug("Dispute status has been set to pending {}", dispute);
|
log.debug("Dispute status has been set to pending {}", dispute.getId());
|
||||||
}
|
}
|
||||||
case FAIL_RESULT -> {
|
case FAIL_RESULT -> {
|
||||||
var errorMessage = TErrorUtil.toStringVal(result.getFailResult().getFailure());
|
var errorMessage = TErrorUtil.toStringVal(result.getFailResult().getFailure());
|
||||||
log.warn("Trying to set failed Dispute status {}, {}", dispute, errorMessage);
|
log.warn("Trying to set failed Dispute status {}, {}", dispute.getId(), errorMessage);
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.failed, errorMessage);
|
disputeDao.update(dispute.getId(), DisputeStatus.failed, errorMessage);
|
||||||
log.debug("Dispute status has been set to failed {}", dispute);
|
log.debug("Dispute status has been set to failed {}", dispute.getId());
|
||||||
}
|
}
|
||||||
|
case ALREADY_EXIST_RESULT ->
|
||||||
|
finishTaskWithManualParsingFlowActivation(dispute, attachments, DisputeStatus.already_exist_created);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
@Transactional(propagation = Propagation.REQUIRED)
|
||||||
void finishTaskWithManualParsingFlowActivation(Dispute dispute, List<Attachment> attachments) {
|
void finishTaskWithManualParsingFlowActivation(Dispute dispute, List<Attachment> attachments, DisputeStatus disputeStatus) {
|
||||||
manualParsingTopic.sendCreated(dispute, attachments);
|
manualParsingTopic.sendCreated(dispute, attachments, disputeStatus);
|
||||||
log.info("Trying to set manual_parsing_created Dispute status {}", dispute);
|
log.info("Trying to set {} Dispute status {}", disputeStatus, dispute);
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.manual_created);
|
disputeDao.update(dispute.getId(), disputeStatus);
|
||||||
log.debug("Dispute status has been set to manual_parsing_created {}", dispute);
|
log.debug("Dispute status has been set to {} {}", disputeStatus, dispute.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private boolean isCapturedBlockedForDispute(Dispute dispute) {
|
private boolean isCapturedBlockedForDispute(Dispute dispute) {
|
||||||
return getTerminal(dispute.getTerminalId()).get().getOptions()
|
return getTerminal(dispute.getTerminalId()).getOptions()
|
||||||
.containsKey(DISPUTE_FLOW_CAPTURED_BLOCKED);
|
.containsKey(DISPUTE_FLOW_CAPTURED_BLOCKED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private boolean isNotProvidersDisputesApiExist(Dispute dispute) {
|
private boolean isNotProvidersDisputesApiExist(Dispute dispute) {
|
||||||
return !getTerminal(dispute.getTerminalId()).get().getOptions()
|
return !getTerminal(dispute.getTerminalId()).getOptions()
|
||||||
.containsKey(DISPUTE_FLOW_PROVIDERS_API_EXIST);
|
.containsKey(DISPUTE_FLOW_PROVIDERS_API_EXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +147,7 @@ public class CreatedDisputesService {
|
|||||||
return invoicingService.getInvoicePayment(dispute.getInvoiceId(), dispute.getPaymentId());
|
return invoicingService.getInvoicePayment(dispute.getInvoiceId(), dispute.getPaymentId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Terminal> getTerminal(Integer terminalId) {
|
private Terminal getTerminal(Integer terminalId) {
|
||||||
return dominantService.getTerminal(new TerminalRef(terminalId));
|
return dominantService.getTerminal(new TerminalRef(terminalId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,6 @@ import org.apache.hc.core5.http.HttpStatus;
|
|||||||
import org.apache.hc.core5.http.io.HttpClientResponseHandler;
|
import org.apache.hc.core5.http.io.HttpClientResponseHandler;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@ -43,20 +41,20 @@ public class ExternalGatewayChecker {
|
|||||||
return httpClient.execute(new HttpGet(getRouteUrl(dispute)), isNotFoundResponse());
|
return httpClient.execute(new HttpGet(getRouteUrl(dispute)), isNotFoundResponse());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private String getRouteUrl(Dispute dispute) {
|
private String getRouteUrl(Dispute dispute) {
|
||||||
return providerRouting.getRouteUrl(getTerminal(dispute.getTerminalId()).get().getOptions(), getProxy(dispute.getProviderId()).get().getUrl());
|
return providerRouting.getRouteUrl(getTerminal(dispute.getTerminalId()).getOptions(), getProxy(dispute.getProviderId()).getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpClientResponseHandler<Boolean> isNotFoundResponse() {
|
private HttpClientResponseHandler<Boolean> isNotFoundResponse() {
|
||||||
return response -> response.getCode() == HttpStatus.SC_NOT_FOUND;
|
return response -> response.getCode() == HttpStatus.SC_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Terminal> getTerminal(Integer terminalId) {
|
private Terminal getTerminal(Integer terminalId) {
|
||||||
return dominantService.getTerminal(new TerminalRef(terminalId));
|
return dominantService.getTerminal(new TerminalRef(terminalId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<ProxyDefinition> getProxy(Integer providerId) {
|
private ProxyDefinition getProxy(Integer providerId) {
|
||||||
return dominantService.getProxy(new ProviderRef(providerId));
|
var provider = dominantService.getProvider(new ProviderRef(providerId));
|
||||||
|
return dominantService.getProxy(provider.getProxy().getRef());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,23 +48,23 @@ public class PendingDisputesService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.debug("GetDisputeForUpdateSkipLocked has been found {}", dispute);
|
log.debug("GetDisputeForUpdateSkipLocked has been found {}", dispute);
|
||||||
log.debug("Trying to get ProviderDispute {}", dispute);
|
log.debug("Trying to get ProviderDispute {}", dispute.getId());
|
||||||
var providerDispute = providerDisputeDao.get(dispute.getId());
|
var providerDispute = providerDisputeDao.get(dispute.getId());
|
||||||
if (providerDispute == null) {
|
if (providerDispute == null) {
|
||||||
var nextCheckAfter = exponentialBackOffPollingService.prepareNextPollingInterval(dispute);
|
var nextCheckAfter = exponentialBackOffPollingService.prepareNextPollingInterval(dispute);
|
||||||
// вернуть в CreatedDisputeService и попробовать создать диспут в провайдере заново
|
// вернуть в CreatedDisputeService и попробовать создать диспут в провайдере заново
|
||||||
log.error("Trying to set created Dispute status, because createDispute() was not success {}", dispute);
|
log.error("Trying to set created Dispute status, because createDispute() was not success {}", dispute.getId());
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.created, nextCheckAfter);
|
disputeDao.update(dispute.getId(), DisputeStatus.created, nextCheckAfter);
|
||||||
log.debug("Dispute status has been set to created {}", dispute);
|
log.debug("Dispute status has been set to created {}", dispute.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pollingInfoService.isDeadline(dispute)) {
|
if (pollingInfoService.isDeadline(dispute)) {
|
||||||
log.error("Trying to set failed Dispute status with POOLING_EXPIRED error reason {}", dispute);
|
log.error("Trying to set failed Dispute status with POOLING_EXPIRED error reason {}", dispute.getId());
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.failed, ErrorReason.POOLING_EXPIRED);
|
disputeDao.update(dispute.getId(), DisputeStatus.failed, ErrorReason.POOLING_EXPIRED);
|
||||||
log.debug("Dispute status has been set to failed {}", dispute);
|
log.debug("Dispute status has been set to failed {}", dispute.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.debug("ProviderDispute has been found {}", dispute);
|
log.debug("ProviderDispute has been found {}", dispute.getId());
|
||||||
var result = remoteClient.checkDisputeStatus(dispute, providerDispute);
|
var result = remoteClient.checkDisputeStatus(dispute, providerDispute);
|
||||||
finishTask(dispute, result);
|
finishTask(dispute, result);
|
||||||
}
|
}
|
||||||
@ -76,13 +76,13 @@ public class PendingDisputesService {
|
|||||||
var changedAmount = result.getStatusSuccess().getChangedAmount().orElse(null);
|
var changedAmount = result.getStatusSuccess().getChangedAmount().orElse(null);
|
||||||
log.info("Trying to set create_adjustment Dispute status {}, {}", dispute, result);
|
log.info("Trying to set create_adjustment Dispute status {}, {}", dispute, result);
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.create_adjustment, changedAmount);
|
disputeDao.update(dispute.getId(), DisputeStatus.create_adjustment, changedAmount);
|
||||||
log.debug("Dispute status has been set to create_adjustment {}", dispute);
|
log.debug("Dispute status has been set to create_adjustment {}", dispute.getId());
|
||||||
}
|
}
|
||||||
case STATUS_FAIL -> {
|
case STATUS_FAIL -> {
|
||||||
var errorMessage = TErrorUtil.toStringVal(result.getStatusFail().getFailure());
|
var errorMessage = TErrorUtil.toStringVal(result.getStatusFail().getFailure());
|
||||||
log.warn("Trying to set failed Dispute status {}, {}", dispute, errorMessage);
|
log.warn("Trying to set failed Dispute status {}, {}", dispute.getId(), errorMessage);
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.failed, errorMessage);
|
disputeDao.update(dispute.getId(), DisputeStatus.failed, errorMessage);
|
||||||
log.debug("Dispute status has been set to failed {}", dispute);
|
log.debug("Dispute status has been set to failed {}", dispute.getId());
|
||||||
}
|
}
|
||||||
case STATUS_PENDING -> {
|
case STATUS_PENDING -> {
|
||||||
// дергаем update() чтоб обновить время вызова next_check_after,
|
// дергаем update() чтоб обновить время вызова next_check_after,
|
||||||
@ -91,7 +91,7 @@ public class PendingDisputesService {
|
|||||||
var nextCheckAfter = exponentialBackOffPollingService.prepareNextPollingInterval(dispute);
|
var nextCheckAfter = exponentialBackOffPollingService.prepareNextPollingInterval(dispute);
|
||||||
log.info("Trying to set pending Dispute status {}, {}", dispute, result);
|
log.info("Trying to set pending Dispute status {}, {}", dispute, result);
|
||||||
disputeDao.update(dispute.getId(), DisputeStatus.pending, nextCheckAfter);
|
disputeDao.update(dispute.getId(), DisputeStatus.pending, nextCheckAfter);
|
||||||
log.debug("Dispute status has been set to pending {}", dispute);
|
log.debug("Dispute status has been set to pending {}", dispute.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import dev.vality.disputes.config.properties.AdaptersConnectionProperties;
|
|||||||
import dev.vality.woody.thrift.impl.http.THSpawnClientBuilder;
|
import dev.vality.woody.thrift.impl.http.THSpawnClientBuilder;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@ -14,20 +15,19 @@ import java.util.concurrent.TimeUnit;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@SuppressWarnings({"AbbreviationAsWordInName", "LineLength"})
|
||||||
public class ProviderIfaceBuilder {
|
public class ProviderIfaceBuilder {
|
||||||
|
|
||||||
private final ProviderRouting providerRouting;
|
private final ProviderRouting providerRouting;
|
||||||
private final AdaptersConnectionProperties adaptersConnectionProperties;
|
private final AdaptersConnectionProperties adaptersConnectionProperties;
|
||||||
|
|
||||||
public ProviderDisputesServiceSrv.Iface build(Map<String, String> options, String url) {
|
@Cacheable(value = "adapters", key = "#root.args[1]", cacheManager = "adaptersCacheManager")
|
||||||
return build(providerRouting.getRouteUrl(options, url));
|
public ProviderDisputesServiceSrv.Iface buildTHSpawnClient(Map<String, String> options, String url) {
|
||||||
}
|
var routeUrl = providerRouting.getRouteUrl(options, url);
|
||||||
|
log.info("Creating new client for url: {}", routeUrl);
|
||||||
private ProviderDisputesServiceSrv.Iface build(String url) {
|
|
||||||
log.info("Creating new client for url: {}", url);
|
|
||||||
return new THSpawnClientBuilder()
|
return new THSpawnClientBuilder()
|
||||||
.withNetworkTimeout((int) TimeUnit.SECONDS.toMillis(adaptersConnectionProperties.getTimeoutSec()))
|
.withNetworkTimeout((int) TimeUnit.SECONDS.toMillis(adaptersConnectionProperties.getTimeoutSec()))
|
||||||
.withAddress(URI.create(url))
|
.withAddress(URI.create(routeUrl))
|
||||||
.build(ProviderDisputesServiceSrv.Iface.class);
|
.build(ProviderDisputesServiceSrv.Iface.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,11 @@ package dev.vality.disputes.schedule.service;
|
|||||||
import dev.vality.disputes.exception.RoutingException;
|
import dev.vality.disputes.exception.RoutingException;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URI;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -19,7 +18,6 @@ public class ProviderRouting {
|
|||||||
private static final String DISPUTES_URL_POSTFIX_DEFAULT = "disputes";
|
private static final String DISPUTES_URL_POSTFIX_DEFAULT = "disputes";
|
||||||
private static final String OPTION_DISPUTES_URL_FIELD_NAME = "disputes_url";
|
private static final String OPTION_DISPUTES_URL_FIELD_NAME = "disputes_url";
|
||||||
|
|
||||||
@Cacheable(value = "adapters", key = "defaultProviderUrl", cacheManager = "adaptersCacheManager")
|
|
||||||
public String getRouteUrl(Map<String, String> options, String defaultProviderUrl) {
|
public String getRouteUrl(Map<String, String> options, String defaultProviderUrl) {
|
||||||
var url = options.get(OPTION_DISPUTES_URL_FIELD_NAME);
|
var url = options.get(OPTION_DISPUTES_URL_FIELD_NAME);
|
||||||
if (ObjectUtils.isEmpty(url)) {
|
if (ObjectUtils.isEmpty(url)) {
|
||||||
@ -31,8 +29,7 @@ public class ProviderRouting {
|
|||||||
private String createDefaultRouteUrl(String defaultProviderUrl) {
|
private String createDefaultRouteUrl(String defaultProviderUrl) {
|
||||||
log.debug("Creating url by appending postfix");
|
log.debug("Creating url by appending postfix");
|
||||||
try {
|
try {
|
||||||
var validUri = new URL(defaultProviderUrl).toURI();
|
return UriComponentsBuilder.fromUri(URI.create(defaultProviderUrl))
|
||||||
return UriComponentsBuilder.fromUri(validUri)
|
|
||||||
.pathSegment(DISPUTES_URL_POSTFIX_DEFAULT)
|
.pathSegment(DISPUTES_URL_POSTFIX_DEFAULT)
|
||||||
.encode()
|
.encode()
|
||||||
.build()
|
.build()
|
||||||
|
@ -90,7 +90,7 @@ public class AccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private InvoicePayment getInvoicePayment(dev.vality.damsel.payment_processing.Invoice invoice, String paymentId) {
|
private InvoicePayment getInvoicePayment(dev.vality.damsel.payment_processing.Invoice invoice, String paymentId) {
|
||||||
log.debug("Processing invoice: {}", invoice);
|
log.debug("Processing invoice: {}", invoice.getInvoice().getId());
|
||||||
return invoice.getPayments().stream()
|
return invoice.getPayments().stream()
|
||||||
.filter(invoicePayment -> paymentId.equals(invoicePayment.getPayment().getId())
|
.filter(invoicePayment -> paymentId.equals(invoicePayment.getPayment().getId())
|
||||||
&& invoicePayment.isSetRoute())
|
&& invoicePayment.isSetRoute())
|
||||||
|
@ -15,6 +15,7 @@ import org.springframework.stereotype.Service;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@SuppressWarnings({"ParameterName", "LineLength"})
|
||||||
public class BouncerServiceImpl implements BouncerService {
|
public class BouncerServiceImpl implements BouncerService {
|
||||||
|
|
||||||
private final BouncerProperties bouncerProperties;
|
private final BouncerProperties bouncerProperties;
|
||||||
@ -23,9 +24,9 @@ public class BouncerServiceImpl implements BouncerService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Resolution getResolution(AccessData accessData) {
|
public Resolution getResolution(AccessData accessData) {
|
||||||
log.debug("Check access with bouncer context: {}", accessData);
|
log.debug("Check access with bouncer context: {}{}", accessData.getInvoice().getInvoice().getId(), accessData.getPayment().getPayment().getId());
|
||||||
var context = bouncerContextFactory.buildContext(accessData);
|
var context = bouncerContextFactory.buildContext(accessData);
|
||||||
log.debug("Built thrift context: {}", context);
|
log.debug("Built thrift context: {}{}", accessData.getInvoice().getInvoice().getId(), accessData.getPayment().getPayment().getId());
|
||||||
try {
|
try {
|
||||||
var judge = bouncerClient.judge(bouncerProperties.getRuleSetId(), context);
|
var judge = bouncerClient.judge(bouncerProperties.getRuleSetId(), context);
|
||||||
log.debug("Have judge: {}", judge);
|
log.debug("Have judge: {}", judge);
|
||||||
|
@ -2,14 +2,14 @@ package dev.vality.disputes.service.external;
|
|||||||
|
|
||||||
import dev.vality.damsel.domain.*;
|
import dev.vality.damsel.domain.*;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
public interface DominantService {
|
public interface DominantService {
|
||||||
|
|
||||||
Currency getCurrency(CurrencyRef currencyRef);
|
Currency getCurrency(CurrencyRef currencyRef);
|
||||||
|
|
||||||
CompletableFuture<Terminal> getTerminal(TerminalRef terminalRef);
|
Terminal getTerminal(TerminalRef terminalRef);
|
||||||
|
|
||||||
CompletableFuture<ProxyDefinition> getProxy(ProviderRef providerRef);
|
ProxyDefinition getProxy(ProxyRef proxyRef);
|
||||||
|
|
||||||
|
Provider getProvider(ProviderRef providerRef);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,8 @@ import dev.vality.disputes.service.external.DominantService;
|
|||||||
import dev.vality.disputes.service.external.impl.dominant.DominantCacheServiceImpl;
|
import dev.vality.disputes.service.external.impl.dominant.DominantCacheServiceImpl;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@ -23,26 +20,18 @@ public class DominantServiceImpl implements DominantService {
|
|||||||
return dominantCacheService.getCurrency(currencyRef);
|
return dominantCacheService.getCurrency(currencyRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Async
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Terminal> getTerminal(TerminalRef terminalRef) {
|
public Terminal getTerminal(TerminalRef terminalRef) {
|
||||||
try {
|
return dominantCacheService.getTerminal(terminalRef);
|
||||||
var terminal = dominantCacheService.getTerminal(terminalRef);
|
|
||||||
return CompletableFuture.completedFuture(terminal);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return CompletableFuture.failedFuture(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Async
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<ProxyDefinition> getProxy(ProviderRef providerRef) {
|
public ProxyDefinition getProxy(ProxyRef proxyRef) {
|
||||||
try {
|
return dominantCacheService.getProxy(proxyRef);
|
||||||
var provider = dominantCacheService.getProvider(providerRef);
|
|
||||||
var proxy = dominantCacheService.getProxy(provider.getProxy().getRef());
|
|
||||||
return CompletableFuture.completedFuture(proxy);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return CompletableFuture.failedFuture(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Provider getProvider(ProviderRef providerRef) {
|
||||||
|
return dominantCacheService.getProvider(providerRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
src/main/java/dev/vality/disputes/service/external/impl/dominant/DominantAsyncService.java
vendored
Normal file
41
src/main/java/dev/vality/disputes/service/external/impl/dominant/DominantAsyncService.java
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package dev.vality.disputes.service.external.impl.dominant;
|
||||||
|
|
||||||
|
import dev.vality.damsel.domain.Currency;
|
||||||
|
import dev.vality.damsel.domain.CurrencyRef;
|
||||||
|
import dev.vality.damsel.domain.Terminal;
|
||||||
|
import dev.vality.damsel.domain.TerminalRef;
|
||||||
|
import dev.vality.disputes.service.external.DominantService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class DominantAsyncService {
|
||||||
|
|
||||||
|
private final DominantService dominantService;
|
||||||
|
|
||||||
|
@Async("dominantAsyncServiceExecutor")
|
||||||
|
public CompletableFuture<Currency> getCurrency(CurrencyRef currencyRef) {
|
||||||
|
try {
|
||||||
|
var currency = dominantService.getCurrency(currencyRef);
|
||||||
|
return CompletableFuture.completedFuture(currency);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return CompletableFuture.failedFuture(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async("dominantAsyncServiceExecutor")
|
||||||
|
public CompletableFuture<Terminal> getTerminal(TerminalRef terminalRef) {
|
||||||
|
try {
|
||||||
|
var terminal = dominantService.getTerminal(terminalRef);
|
||||||
|
return CompletableFuture.completedFuture(terminal);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return CompletableFuture.failedFuture(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,20 +19,19 @@ public class DominantCacheServiceImpl {
|
|||||||
private final RepositoryClientSrv.Iface dominantClient;
|
private final RepositoryClientSrv.Iface dominantClient;
|
||||||
|
|
||||||
@Cacheable(value = "currencies", key = "#currencyRef.symbolic_code", cacheManager = "currenciesCacheManager")
|
@Cacheable(value = "currencies", key = "#currencyRef.symbolic_code", cacheManager = "currenciesCacheManager")
|
||||||
public Currency getCurrency(CurrencyRef currencyRef) throws NotFoundException {
|
public Currency getCurrency(CurrencyRef currencyRef) {
|
||||||
return getCurrency(currencyRef, Reference.head(new Head()));
|
return getCurrency(currencyRef, Reference.head(new Head()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Currency getCurrency(CurrencyRef currencyRef, Reference revisionReference)
|
private Currency getCurrency(CurrencyRef currencyRef, Reference revisionReference) {
|
||||||
throws NotFoundException {
|
|
||||||
log.debug("Trying to get currency, currencyRef='{}', revisionReference='{}'", currencyRef, revisionReference);
|
log.debug("Trying to get currency, currencyRef='{}', revisionReference='{}'", currencyRef, revisionReference);
|
||||||
try {
|
try {
|
||||||
var reference = new dev.vality.damsel.domain.Reference();
|
var reference = new dev.vality.damsel.domain.Reference();
|
||||||
reference.setCurrency(currencyRef);
|
reference.setCurrency(currencyRef);
|
||||||
var versionedObject = checkoutObject(revisionReference, reference);
|
var versionedObject = checkoutObject(revisionReference, reference);
|
||||||
var currency = versionedObject.getObject().getCurrency().getData();
|
var currency = versionedObject.getObject().getCurrency().getData();
|
||||||
log.debug("Currency has been found, currencyRef='{}', revisionReference='{}', currency='{}'",
|
log.debug("Currency has been found, currencyRef='{}', revisionReference='{}'",
|
||||||
currencyRef, revisionReference, currency);
|
currencyRef, revisionReference);
|
||||||
return currency;
|
return currency;
|
||||||
} catch (VersionNotFound | ObjectNotFound ex) {
|
} catch (VersionNotFound | ObjectNotFound ex) {
|
||||||
throw new NotFoundException(String.format("Version not found, currencyRef='%s', revisionReference='%s'",
|
throw new NotFoundException(String.format("Version not found, currencyRef='%s', revisionReference='%s'",
|
||||||
@ -48,8 +47,7 @@ public class DominantCacheServiceImpl {
|
|||||||
return getTerminal(terminalRef, Reference.head(new Head()));
|
return getTerminal(terminalRef, Reference.head(new Head()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Terminal getTerminal(TerminalRef terminalRef, Reference revisionReference)
|
public Terminal getTerminal(TerminalRef terminalRef, Reference revisionReference) {
|
||||||
throws NotFoundException {
|
|
||||||
log.debug("Trying to get terminal from dominant, terminalRef='{}', revisionReference='{}'", terminalRef,
|
log.debug("Trying to get terminal from dominant, terminalRef='{}', revisionReference='{}'", terminalRef,
|
||||||
revisionReference);
|
revisionReference);
|
||||||
try {
|
try {
|
||||||
@ -57,8 +55,8 @@ public class DominantCacheServiceImpl {
|
|||||||
reference.setTerminal(terminalRef);
|
reference.setTerminal(terminalRef);
|
||||||
var versionedObject = checkoutObject(revisionReference, reference);
|
var versionedObject = checkoutObject(revisionReference, reference);
|
||||||
var terminal = versionedObject.getObject().getTerminal().getData();
|
var terminal = versionedObject.getObject().getTerminal().getData();
|
||||||
log.debug("Terminal has been found, terminalRef='{}', revisionReference='{}', terminal='{}'",
|
log.debug("Terminal has been found, terminalRef='{}', revisionReference='{}'",
|
||||||
terminalRef, revisionReference, terminal);
|
terminalRef, revisionReference);
|
||||||
return terminal;
|
return terminal;
|
||||||
} catch (VersionNotFound | ObjectNotFound ex) {
|
} catch (VersionNotFound | ObjectNotFound ex) {
|
||||||
throw new NotFoundException(String.format("Version not found, terminalRef='%s', revisionReference='%s'",
|
throw new NotFoundException(String.format("Version not found, terminalRef='%s', revisionReference='%s'",
|
||||||
@ -74,8 +72,7 @@ public class DominantCacheServiceImpl {
|
|||||||
return getProvider(providerRef, Reference.head(new Head()));
|
return getProvider(providerRef, Reference.head(new Head()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Provider getProvider(ProviderRef providerRef, Reference revisionReference)
|
private Provider getProvider(ProviderRef providerRef, Reference revisionReference) {
|
||||||
throws NotFoundException {
|
|
||||||
log.debug("Trying to get provider from dominant, providerRef='{}', revisionReference='{}'", providerRef,
|
log.debug("Trying to get provider from dominant, providerRef='{}', revisionReference='{}'", providerRef,
|
||||||
revisionReference);
|
revisionReference);
|
||||||
try {
|
try {
|
||||||
@ -83,8 +80,8 @@ public class DominantCacheServiceImpl {
|
|||||||
reference.setProvider(providerRef);
|
reference.setProvider(providerRef);
|
||||||
var versionedObject = checkoutObject(revisionReference, reference);
|
var versionedObject = checkoutObject(revisionReference, reference);
|
||||||
var provider = versionedObject.getObject().getProvider().getData();
|
var provider = versionedObject.getObject().getProvider().getData();
|
||||||
log.debug("Provider has been found, providerRef='{}', revisionReference='{}', terminal='{}'",
|
log.debug("Provider has been found, providerRef='{}', revisionReference='{}'",
|
||||||
providerRef, revisionReference, provider);
|
providerRef, revisionReference);
|
||||||
return provider;
|
return provider;
|
||||||
} catch (VersionNotFound | ObjectNotFound ex) {
|
} catch (VersionNotFound | ObjectNotFound ex) {
|
||||||
throw new NotFoundException(String.format("Version not found, providerRef='%s', revisionReference='%s'",
|
throw new NotFoundException(String.format("Version not found, providerRef='%s', revisionReference='%s'",
|
||||||
@ -101,8 +98,7 @@ public class DominantCacheServiceImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ProxyDefinition getProxy(ProxyRef proxyRef, Reference revisionReference)
|
private ProxyDefinition getProxy(ProxyRef proxyRef, Reference revisionReference) {
|
||||||
throws NotFoundException {
|
|
||||||
log.debug("Trying to get proxy from dominant, proxyRef='{}', revisionReference='{}'", proxyRef,
|
log.debug("Trying to get proxy from dominant, proxyRef='{}', revisionReference='{}'", proxyRef,
|
||||||
revisionReference);
|
revisionReference);
|
||||||
try {
|
try {
|
||||||
|
@ -91,6 +91,9 @@ dispute:
|
|||||||
fixedDelayCreated: 5000
|
fixedDelayCreated: 5000
|
||||||
fixedDelayPending: 5000
|
fixedDelayPending: 5000
|
||||||
fixedDelayCreateAdjustments: 5000
|
fixedDelayCreateAdjustments: 5000
|
||||||
|
initialDelayCreated: 5000
|
||||||
|
initialDelayPending: 5000
|
||||||
|
initialDelayCreateAdjustments: 5000
|
||||||
isScheduleCreatedEnabled: true
|
isScheduleCreatedEnabled: true
|
||||||
isSchedulePendingEnabled: true
|
isSchedulePendingEnabled: true
|
||||||
isScheduleCreateAdjustmentsEnabled: true
|
isScheduleCreateAdjustmentsEnabled: true
|
||||||
@ -105,3 +108,10 @@ manual-parsing-topic:
|
|||||||
testcontainers:
|
testcontainers:
|
||||||
postgresql:
|
postgresql:
|
||||||
tag: '11.4'
|
tag: '11.4'
|
||||||
|
|
||||||
|
http-client:
|
||||||
|
requestTimeout: 60000
|
||||||
|
poolTimeout: 10000
|
||||||
|
connectionTimeout: 10000
|
||||||
|
maxTotalPooling: 200
|
||||||
|
defaultMaxPerRoute: 200
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TYPE dspt.dispute_status ADD VALUE 'already_exist_created';
|
@ -1,26 +1,47 @@
|
|||||||
package dev.vality.disputes.dao;
|
package dev.vality.disputes.dao;
|
||||||
|
|
||||||
|
import dev.vality.disputes.dao.config.PostgresqlSpringBootITest;
|
||||||
import dev.vality.disputes.domain.tables.pojos.Dispute;
|
import dev.vality.disputes.domain.tables.pojos.Dispute;
|
||||||
import dev.vality.testcontainers.annotations.DefaultSpringBootTest;
|
import dev.vality.disputes.exception.NotFoundException;
|
||||||
import dev.vality.testcontainers.annotations.postgresql.PostgresqlTestcontainerSingleton;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import static dev.vality.testcontainers.annotations.util.RandomBeans.random;
|
import static dev.vality.testcontainers.annotations.util.RandomBeans.random;
|
||||||
|
import static dev.vality.testcontainers.annotations.util.ValuesGenerator.generateId;
|
||||||
|
import static dev.vality.testcontainers.annotations.util.ValuesGenerator.generateLong;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
@PostgresqlTestcontainerSingleton
|
@PostgresqlSpringBootITest
|
||||||
@DefaultSpringBootTest
|
|
||||||
public class DisputeDaoTest {
|
public class DisputeDaoTest {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DisputeDao disputeDao;
|
private DisputeDao disputeDao;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void insertAndFindTest() {
|
public void testInsertAndFind() {
|
||||||
var random = random(Dispute.class);
|
var random = random(Dispute.class);
|
||||||
disputeDao.save(random);
|
disputeDao.save(random);
|
||||||
assertEquals(random,
|
assertEquals(random,
|
||||||
disputeDao.get(random.getId(), random.getInvoiceId(), random.getPaymentId()));
|
disputeDao.get(random.getId(), random.getInvoiceId(), random.getPaymentId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotFoundException() {
|
||||||
|
assertThrows(NotFoundException.class,
|
||||||
|
() -> disputeDao.get(generateLong(), generateId(), generateId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultiInsertAndFind() {
|
||||||
|
var random = random(Dispute.class);
|
||||||
|
random.setId(null);
|
||||||
|
random.setInvoiceId("setInvoiceId");
|
||||||
|
random.setPaymentId("setPaymentId");
|
||||||
|
disputeDao.save(random);
|
||||||
|
disputeDao.save(random);
|
||||||
|
disputeDao.save(random);
|
||||||
|
assertEquals(3,
|
||||||
|
disputeDao.get(random.getInvoiceId(), random.getPaymentId()).size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package dev.vality.disputes.dao.config;
|
||||||
|
|
||||||
|
import dev.vality.disputes.dao.config.testconfiguration.MockedUnimportantServicesConfig;
|
||||||
|
import dev.vality.testcontainers.annotations.DefaultSpringBootTest;
|
||||||
|
import dev.vality.testcontainers.annotations.postgresql.PostgresqlTestcontainerSingleton;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@PostgresqlTestcontainerSingleton
|
||||||
|
@DefaultSpringBootTest
|
||||||
|
@Import(MockedUnimportantServicesConfig.class)
|
||||||
|
public @interface PostgresqlSpringBootITest {
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package dev.vality.disputes.dao.config.testconfiguration;
|
||||||
|
|
||||||
|
import dev.vality.disputes.schedule.TaskCreateAdjustmentsService;
|
||||||
|
import dev.vality.disputes.schedule.TaskCreatedDisputesService;
|
||||||
|
import dev.vality.disputes.schedule.TaskPendingDisputesService;
|
||||||
|
import org.springframework.boot.test.context.TestConfiguration;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
|
||||||
|
@TestConfiguration
|
||||||
|
public class MockedUnimportantServicesConfig {
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private TaskCreatedDisputesService taskCreatedDisputesService;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private TaskPendingDisputesService taskPendingDisputesService;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private TaskCreateAdjustmentsService taskCreateAdjustmentsService;
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user