PROX-364: add libs

This commit is contained in:
avcherkasov 2019-10-30 18:57:00 +03:00
parent d35b9b64ee
commit 1a99b058c8
45 changed files with 1288 additions and 1 deletions

78
.gitignore vendored Normal file
View File

@ -0,0 +1,78 @@
# Created by .ignore support plugin (hsz.mobi)
.eunit
deps
*.o
*.beam
*.plt
erl_crash.dump
ebin/*.beam
rel/example_project
.concrete/DEV_MODE
.rebar
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/
.idea/workspace.xml
.idea/tasks.xml
.idea/dictionaries
.idea/vcs.xml
.idea/jsLibraryMappings.xml
# Sensitive or high-churn files:
.idea/dataSources.ids
.idea/dataSources.xml
.idea/dataSources.local.xml
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
# Gradle:
.idea/gradle.xml
.idea/libraries
# Mongo Explorer plugin:
.idea/mongoSettings.xml
*.iws
*.ipr
*.iml
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
env.list

4
.gitmodules vendored Normal file
View File

@ -0,0 +1,4 @@
[submodule "build_utils"]
path = build_utils
url = git@github.com:rbkmoney/build_utils.git
branch = master

15
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,15 @@
#!groovy
build('adapter-cashreg-spring-boot-starter', 'docker-host') {
checkoutRepo()
loadBuildUtils()
def javaLibPipeline
runStage('load JavaLib pipeline') {
javaLibPipeline = load("build_utils/jenkins_lib/pipeJavaLib.groovy")
}
def buildImageTag = "fcf116dd775cc2e91bffb6a36835754e3f2d5321"
javaLibPipeline(buildImageTag)
}

View File

@ -1 +1,75 @@
# adapter-cashreg-spring-boot-starter
# adapter-cashreg-spring-boot-starter
Вспомогательная библиотека для адаптеров взаимодействующих с провайдерами электронных касс по отправке чеков онлайн
### Разработчики
- [Anatoly Cherkasov](https://github.com/avcherkasov)
### Настройки
Добавить в `pom.xml` в зависимости
```
<dependency>
<groupId>com.rbkmoney</groupId>
<artifactId>adapter-cashreg-spring-boot-starter</artifactId>
<version>${adapter-cashreg-spring-boot-starter.version}</version>
</dependency>
```
В зависимостях также должны быть указаны
```
<dependency>
<groupId>com.rbkmoney.woody</groupId>
<artifactId>woody-thrift</artifactId>
<version>${woody-thrift.version}</version>
</dependency>
<dependency>
<groupId>com.rbkmoney</groupId>
<artifactId>damsel</artifactId>
<version>${damsel.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet-api.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-api.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.github.seancfoley</groupId>
<artifactId>ipaddress</artifactId>
<version>${ipaddress.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>com.rbkmoney</groupId>
<artifactId>error-mapping-java</artifactId>
<version>${error-mapping.version}</version>
</dependency>
<dependency>
<groupId>com.rbkmoney</groupId>
<artifactId>damsel</artifactId>
<version>${damsel.version}</version>
</dependency>
```

1
build_utils Submodule

@ -0,0 +1 @@
Subproject commit 4a09386542ab4b98317a787fd6e06e0d3a1e38d6

175
pom.xml Normal file
View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rbkmoney</groupId>
<artifactId>adapter-cashreg-spring-boot-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>8</java.version>
<spring-boot.version>2.1.1.RELEASE</spring-boot.version>
<damsel-utils.version>2.1.9</damsel-utils.version>
<damsel.version>1.303-d99319c</damsel.version>
<serializer.version>0.6.7</serializer.version>
<adapter-common-lib.version>0.0.8</adapter-common-lib.version>
<error-mapping.version>1.0.4</error-mapping.version>
<cashreg-proto.version>1.9-9c79023</cashreg-proto.version>
</properties>
<dependencies>
<!--third party-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.seancfoley</groupId>
<artifactId>ipaddress</artifactId>
<version>4.2.0</version>
<scope>provided</scope>
</dependency>
<!--spring-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency>
<!--rbk-->
<dependency>
<groupId>com.rbkmoney</groupId>
<artifactId>cashreg-proto</artifactId>
<version>${cashreg-proto.version}</version>
</dependency>
<dependency>
<groupId>com.rbkmoney</groupId>
<artifactId>adapter-common-lib</artifactId>
<version>${adapter-common-lib.version}</version>
</dependency>
<dependency>
<groupId>com.rbkmoney</groupId>
<artifactId>error-mapping-java</artifactId>
<version>${error-mapping.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.rbkmoney</groupId>
<artifactId>damsel</artifactId>
<version>${damsel.version}</version>
<scope>provided</scope>
</dependency>
<!-- test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<distributionManagement>
<downloadUrl>http://java-nexus.msk1.rbkmoney.net:8081/nexus/content/groups/public</downloadUrl>
<repository>
<uniqueVersion>false</uniqueVersion>
<id>releases</id>
<name>RBKmoney releases repository</name>
<url>http://java-nexus.msk1.rbkmoney.net:8081/nexus/content/repositories/releases</url>
<layout>default</layout>
</repository>
<snapshotRepository>
<uniqueVersion>true</uniqueVersion>
<id>snapshots</id>
<name>RBKmoney snapshots repository</name>
<url>http://java-nexus.msk1.rbkmoney.net:8081/nexus/content/repositories/snapshots</url>
<layout>default</layout>
</snapshotRepository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<append>true</append>
</configuration>
<executions>
<execution>
<id>agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@ -0,0 +1,27 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.config;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.utils.converter.ip.ConverterIp;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* application.yml
* <pre>
* {@code
* converterIp:
* nat64prefix: "2a04:4a00:5:10ff:4:1:"
* }
* </pre>
*
* @see ConverterIp
*/
@Configuration
public class ConverterIpConfiguration {
@Bean
ConverterIp converterIp(@Value("${converterIp.nat64prefix:" + ConverterIp.NAT_64_PREFIX + "}") String nat64prefix) {
return new ConverterIp(nat64prefix);
}
}

View File

@ -0,0 +1,25 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.config;
import com.rbkmoney.adapter.common.mapper.SimpleErrorMapping;
import com.rbkmoney.error.mapping.ErrorMapping;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import java.io.IOException;
@Configuration
public class ErrorMappingConfiguration {
@Value("${error-mapping.file}")
private Resource errorMappingFilePath;
@Value("${error-mapping.patternReason:\"'%s' - '%s'\"}")
private String errorMappingPattern;
@Bean
public ErrorMapping errorMapping() throws IOException {
return new SimpleErrorMapping(errorMappingFilePath, errorMappingPattern).getErrorMapping();
}
}

View File

@ -0,0 +1,21 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.config.properties;
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;
import javax.validation.constraints.NotEmpty;
@Getter
@Setter
@Configuration
@ConfigurationProperties("adapter")
@Validated
public class AdapterProperties {
@NotEmpty
private String url;
}

View File

@ -0,0 +1,24 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.config.properties;
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;
import javax.validation.constraints.NotNull;
@Configuration
@ConfigurationProperties("time.config")
@Validated
@Getter
@Setter
public class TimerProperties {
@NotNull
private int maxTimePolling;
@NotNull
private int pollingDelay;
}

View File

@ -0,0 +1,19 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.constant;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum Error {
DEFAULT_ERROR_CODE("error", "error"),
UNKNOWN("unknown_code", "Unknown error!"),
EMPTY_BODY("Empty body", "Empty body"),
SLEEP_TIMEOUT("Sleep timeout", "Max time pool limit reached");
private final String code;
private final String message;
}

View File

@ -0,0 +1,38 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.constant;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum OptionalField {
URL("url"),
GROUP("group"),
LOGIN("login"),
PASS("pass"),
CLIENT_ID("client_id"),
TAX_ID("tax_id"),
TAX_MODE("tax_mode"),
COMPANY_INN("company_inn"),
COMPANY_NAME("company_name"),
COMPANY_ADDRESS("company_address"),
COMPANY_EMAIL("company_email"),
POLLING_DELAY("polling_delay"),
MAX_TIME_POLLING("max_time_polling"),
TIMER_TIMEOUT("timer_timeout"),
TIMER_ADD_TIME("timer_add_time"),
PRIVATE_KEY("private_key"),
KEY("key"),
PAYMENT_METHOD("payment_method"),
PAYMENT_OBJECT("payment_object");
private final String field;
}

View File

@ -0,0 +1,8 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.constant;
public enum TargetType {
DEBIT,
CREDIT,
REFUND_DEBIT,
REFUND_CREDIT
}

View File

@ -0,0 +1,36 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.converter;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.AdapterContext;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.serializer.AdapterSerializer;
import com.rbkmoney.damsel.cashreg.provider.CashRegContext;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class CashRegAdapterContextConveter implements Converter<CashRegContext, AdapterContext> {
private static final byte[] DEFAULT_STATE = new byte[0];
private final AdapterSerializer serializer;
@Override
public AdapterContext convert(CashRegContext context) {
AdapterContext adapterContext = new AdapterContext();
byte[] state = getState(context);
if (state != null && state.length > 0) {
return serializer.read(state);
}
return adapterContext;
}
private byte[] getState(CashRegContext context) {
if (context.getSession().isSetState()) {
return context.getSession().getState();
}
return DEFAULT_STATE;
}
}

View File

@ -0,0 +1,60 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.converter;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.utils.extractors.TypeExtractor;
import com.rbkmoney.damsel.cashreg.provider.CashRegContext;
import com.rbkmoney.damsel.cashreg.provider.CashRegProviderSrv;
import com.rbkmoney.damsel.cashreg.provider.CashRegResult;
import com.rbkmoney.woody.api.flow.error.WErrorDefinition;
import com.rbkmoney.woody.api.flow.error.WErrorType;
import com.rbkmoney.woody.api.flow.error.WRuntimeException;
import com.rbkmoney.woody.api.trace.context.TraceContext;
import com.rbkmoney.woody.thrift.impl.http.error.THTransportErrorMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.thrift.TException;
@Slf4j
@RequiredArgsConstructor
public class CashRegAdapterServiceLogDecorator implements CashRegProviderSrv.Iface {
private final CashRegProviderSrv.Iface adapterService;
@Override
public CashRegResult register(CashRegContext cashRegContext) throws TException {
String cashRegType = TypeExtractor.extractCashRegType(cashRegContext);
String cashRegId = cashRegContext.getCashregId();
log.info("Started: {} with cashRegId {}", cashRegType, cashRegId);
try {
CashRegResult regResult = adapterService.register(cashRegContext);
log.info("Finished {} with cashRegId {}", cashRegType, cashRegId);
return regResult;
} catch (Exception ex) {
String message = "Failed handle " + cashRegType + " with cashRegId " + cashRegId;
logMessage(ex, message);
throw ex;
}
}
private static void logMessage(Exception ex, String message) {
if (isUndefinedResultOrUnavailable(ex)) {
log.warn(message, ex);
} else {
log.error(message, ex);
}
}
private static boolean isUndefinedResultOrUnavailable(Exception exception) {
WErrorDefinition definition;
if (exception instanceof WRuntimeException) {
definition = ((WRuntimeException) exception).getErrorDefinition();
} else {
THTransportErrorMapper errorMapper = new THTransportErrorMapper();
definition = errorMapper.mapToDef(exception, TraceContext.getCurrentTraceData().getActiveSpan());
}
boolean undefined = definition != null && WErrorType.UNDEFINED_RESULT.getKey().equals(definition.getErrorType().getKey());
boolean unavailable = definition != null && WErrorType.UNAVAILABLE_RESULT.getKey().equals(definition.getErrorType().getKey());
return undefined || unavailable;
}
}

View File

@ -0,0 +1,7 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.exception;
public class UnknownTargetTypeException extends RuntimeException {
public UnknownTargetTypeException() {
super("Unknown target type!");
}
}

View File

@ -0,0 +1,9 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.exception;
import org.apache.thrift.TException;
public class UnsupportedMethodException extends TException {
public UnsupportedMethodException() {
super("Unsupported method");
}
}

View File

@ -0,0 +1,19 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.exception;
public class ValidationException extends RuntimeException {
public ValidationException() {
super();
}
public ValidationException(String message) {
super(message);
}
public ValidationException(String message, Throwable cause) {
super(message, cause);
}
public ValidationException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,24 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.flow;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.ExitStateModel;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.StateModel;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.Step;
import org.springframework.stereotype.Component;
@Component
public class DefaultStepResolverImpl implements StepResolver<StateModel, ExitStateModel> {
@Override
public Step resolveEntry(StateModel stateModel) {
if(stateModel.getStep() == null) {
return Step.CREATE;
}
return Step.CHECK_STATUS;
}
@Override
public Step resolveExit(ExitStateModel stateModel) {
return stateModel.getNextStep();
}
}

View File

@ -0,0 +1,10 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.flow;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.ExitStateModel;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.StateModel;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.Step;
public interface StepResolver<T extends StateModel, R extends ExitStateModel> {
Step resolveEntry(T stateModel);
Step resolveExit(R stateModel);
}

View File

@ -0,0 +1,26 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.flow;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.constant.TargetType;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.exception.UnknownTargetTypeException;
import org.springframework.stereotype.Component;
@Component
public class TargetTypeResolver {
public TargetType resolve(com.rbkmoney.damsel.cashreg.type.Type type) {
if (type != null) {
if (type.isSetCredit()) {
return TargetType.CREDIT;
} else if (type.isSetDebit()) {
return TargetType.DEBIT;
} else if (type.isSetRefundDebit()) {
return TargetType.REFUND_DEBIT;
} else if (type.isSetRefundCredit()) {
return TargetType.REFUND_CREDIT;
}
}
throw new UnknownTargetTypeException();
}
}

View File

@ -0,0 +1,12 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.handler;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.EntryStateModel;
import org.apache.thrift.TException;
public interface CommonHandler<T, R, E extends EntryStateModel> {
boolean isHandler(final E entryStateModel);
T handle(E context) throws TException;
}

View File

@ -0,0 +1,27 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.handler;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.EntryStateModel;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.ExitStateModel;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.processor.Processor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.converter.Converter;
import java.util.function.Function;
@Slf4j
@RequiredArgsConstructor
public abstract class CommonHandlerImpl<T extends ExitStateModel, P, R, E extends EntryStateModel> implements CommonHandler<T, R, E> {
private final Function<P, R> requestFunction;
private final Converter<E, P> converter;
private final Processor<T, E, R> processor;
@Override
public T handle(E entryStateModel) {
P request = converter.convert(entryStateModel);
R response = requestFunction.apply(request);
return processor.process(response, entryStateModel);
}
}

View File

@ -0,0 +1,30 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.time.Instant;
@Getter
@Setter
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class AdapterContext {
@JsonProperty(value = "max_date_time_polling")
private Instant maxDateTimePolling;
private Step nextStep;
@JsonProperty(value = "cashreg_id")
private String cashRegId;
@JsonProperty(value = "receipt_id")
private String receiptId;
}

View File

@ -0,0 +1,17 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import lombok.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Auth {
@ToString.Exclude
private String login;
@ToString.Exclude
private String pass;
}

View File

@ -0,0 +1,17 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@Builder
@ToString
public class Client {
private String email;
private String phone;
private String sno;
}

View File

@ -0,0 +1,18 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@Builder
@ToString
public class Company {
private String email;
private String sno;
private String inn;
private String paymentAddress;
}

View File

@ -0,0 +1,12 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class EntryStateModel {
private OperationModel operationModel;
private StateModel stateModel;
}

View File

@ -0,0 +1,21 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import com.rbkmoney.damsel.cashreg.CashRegInfo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExitStateModel {
private Step nextStep;
private String errorCode;
private String errorMessage;
private AdapterContext adapterContext;
private EntryStateModel entryStateModel;
private String cashRegId;
private CashRegInfo cashRegInfo;
}

View File

@ -0,0 +1,67 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.math.BigDecimal;
@ToString
@Getter
@Setter
@Builder
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Items {
/**
* Наименование товара
* Максимальная длина строки 64 символа.
*/
private String name;
/**
* Цена в рублях:
* - целая часть не более 8 знаков;
* - дробная часть не более 2 знаков
*/
private BigDecimal price;
/**
* Количество/вес:
* - целая часть не более 8 знаков;
* - дробная часть не более 3 знаков.
*/
private BigDecimal quantity;
/**
* Сумма позиции в рублях:
* - целая часть не более 8 знаков;
* - дробная часть не более 2 знаков.
* Если значение sum меньше/больше значения (price*quantity), то разница является
* скидкой/надбавкой на позицию соответственно. В этих случаях происходит
* перерасчёт поля price для равномерного распределения скидки/надбавки по позициям.
*/
private BigDecimal sum;
/**
* Единица измерения товара, работы, услуги, платежа, выплаты, иного предмета расчета.
* Максимальная длина строки 16 символов.
*/
@JsonProperty("measurement_unit")
private String measurementUnit;
@JsonProperty("payment_method")
private String paymentMethod;
@JsonProperty("payment_object")
private String paymentObject;
@JsonProperty("vat")
private Vat vat;
}

View File

@ -0,0 +1,35 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
@Data
@Builder
@AllArgsConstructor
public class OperationModel {
private String cashRegId;
private Auth auth;
private Company company;
private Client client;
private List<Items> items;
private List<Payments> payments;
private List<Vat> vats;
private BigDecimal total;
@ToString.Exclude
private Map<String, String> options;
private String callbackUrl;
}

View File

@ -0,0 +1,18 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.math.BigDecimal;
@Getter
@Setter
@Builder
@ToString
public class Payments {
private Integer type;
private BigDecimal sum;
}

View File

@ -0,0 +1,13 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.constant.TargetType;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class StateModel {
private TargetType targetType;
private AdapterContext adapterContext;
private Step step;
}

View File

@ -0,0 +1,11 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum Step {
CHECK_DUPLICATION,
CREATE,
CHECK_STATUS
}

View File

@ -0,0 +1,17 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.math.BigDecimal;
@ToString
@Getter
@Setter
@Builder
public class Vat {
private String type;
private BigDecimal sum;
}

View File

@ -0,0 +1,8 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.processor;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.EntryStateModel;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.ExitStateModel;
public interface Processor<T extends ExitStateModel, E extends EntryStateModel, R> {
T process(R response, E context);
}

View File

@ -0,0 +1,28 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.serializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.AdapterContext;
import com.rbkmoney.adapter.common.serializer.StateSerializer;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class AdapterSerializer extends StateSerializer<AdapterContext> {
public AdapterSerializer(ObjectMapper mapper) {
super(mapper);
}
public AdapterContext read(byte[] data) {
if (data == null) {
return new AdapterContext();
}
try {
return getMapper().readValue(data, AdapterContext.class);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
}

View File

@ -0,0 +1,11 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.service;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.ExitStateModel;
import com.rbkmoney.damsel.cashreg.provider.Intent;
public interface IntentService {
Intent getFailureByCode(ExitStateModel exitStateModel);
Intent getFailureByCodeAndDesc(ExitStateModel exitStateModel);
Intent getSuccess(ExitStateModel exitStateModel);
Intent getSleep(ExitStateModel exitStateModel);
}

View File

@ -0,0 +1,46 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.service;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.config.properties.TimerProperties;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.model.ExitStateModel;
import com.rbkmoney.damsel.cashreg.base.Timer;
import com.rbkmoney.damsel.cashreg.provider.*;
import com.rbkmoney.error.mapping.ErrorMapping;
import com.rbkmoney.java.damsel.utils.extractors.OptionsExtractors;
import lombok.RequiredArgsConstructor;
import java.time.Instant;
@RequiredArgsConstructor
public class IntentServiceImpl implements IntentService {
private final ErrorMapping errorMapping;
private final TimerProperties timerProperties;
public Intent getFailureByCode(ExitStateModel exitStateModel) {
return Intent.finish(new FinishIntent(FinishStatus.failure(errorMapping.mapFailure(exitStateModel.getErrorCode()))));
}
public Intent getFailureByCodeAndDesc(ExitStateModel exitStateModel) {
return Intent.finish(new FinishIntent(FinishStatus.failure(errorMapping.mapFailure(exitStateModel.getErrorCode(), exitStateModel.getErrorMessage()))));
}
public Intent getSuccess(ExitStateModel exitStateModel) {
return Intent.finish(new FinishIntent(FinishStatus.success(new Success())));
}
public Intent getSleep(ExitStateModel exitStateModel) {
if (exitStateModel.getAdapterContext().getMaxDateTimePolling() == null) {
throw new IllegalArgumentException("Need to specify 'maxTimePoolingMillis' before sleep");
}
if (exitStateModel.getAdapterContext().getMaxDateTimePolling().getEpochSecond() < Instant.now().getEpochSecond()) {
return Intent.finish(new FinishIntent(FinishStatus.failure(errorMapping.mapFailure(
com.rbkmoney.adapter.cashreg.spring.boot.starter.constant.Error.SLEEP_TIMEOUT.getCode(),
com.rbkmoney.adapter.cashreg.spring.boot.starter.constant.Error.SLEEP_TIMEOUT.getMessage()
))));
}
int timerPollingDelay = OptionsExtractors.extractPollingDelay(exitStateModel.getEntryStateModel().getOperationModel().getOptions(), timerProperties.getPollingDelay());
return Intent.sleep(new SleepIntent(new Timer(Timer.timeout(timerPollingDelay))));
}
}

View File

@ -0,0 +1,62 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.utils.converter.ip;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.config.ConverterIpConfiguration;
import inet.ipaddr.AddressStringException;
import inet.ipaddr.IPAddress;
import inet.ipaddr.IPAddressString;
import inet.ipaddr.ipv6.IPv6Address;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Converter IPv4 to IPv6
* <pre>
* {@code
* ConverterIp converterIp = new ConverterIp("2a04:4a00:5:10ff:4:1:");
* String url = converterIp.replaceIpv4ToIpv6("185.31.132.50"); // 2a04:4a00:5:966:d464:b2f8:a849:3ea8
* }
* </pre>
*
* @see ConverterIpConfiguration
*/
public class ConverterIp {
public static final String NAT_64_PREFIX = "2a04:4a00:5:10ff:4:1:";
private static final String REGEXP_IP = "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})";
private static final String DEFAULT_NAT_64_PREFIX = "::ffff:";
private String nat64prefix;
public ConverterIp() {
this.nat64prefix = NAT_64_PREFIX;
}
public ConverterIp(String nat64prefix) {
this.nat64prefix = nat64prefix;
}
public String replaceIpv4ToIpv6(String url) {
Pattern p = Pattern.compile(REGEXP_IP);
Matcher m = p.matcher(url);
if (m.find()) {
String ip = m.group(1);
IPAddress address;
try {
address = new IPAddressString(ip).toAddress();
} catch (AddressStringException e) {
throw new IllegalArgumentException(e);
}
IPv6Address ipv6Address = address.toIPv6();
String canonicalAddress = ipv6Address.toCanonicalString();
String suffix = canonicalAddress.replace(DEFAULT_NAT_64_PREFIX, this.nat64prefix);
return url.replace(ip, "[" + suffix + "]");
}
return url;
}
}

View File

@ -0,0 +1,51 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.utils.creators;
import com.rbkmoney.damsel.cashreg.CashRegInfo;
import com.rbkmoney.damsel.cashreg.base.Timer;
import com.rbkmoney.damsel.cashreg.provider.*;
import com.rbkmoney.damsel.domain.Failure;
public class CashRegProviderCreators {
public static Intent createFinishIntentSuccess() {
return Intent.finish(new FinishIntent(createFinishStatusSuccess()));
}
public static Intent createFinishIntentFailure(Failure failure) {
return Intent.finish(new FinishIntent(createFinishStatusFailure(failure)));
}
public static FinishStatus createFinishStatusSuccess() {
return FinishStatus.success(new Success());
}
public static FinishStatus createFinishStatusFailure(Failure failure) {
return FinishStatus.failure(failure);
}
public static Failure createFailure(String code) {
return createFailure(code, code);
}
public static Failure createFailure(String code, String reason) {
return new Failure().setCode(code).setReason(reason);
}
public static CashRegResult createCashRegResult(Intent intent, byte[] state, CashRegInfo cashRegInfo) {
return new CashRegResult().setIntent(intent).setCashregInfo(cashRegInfo).setState(state);
}
public static Intent createIntentWithSleepIntent(Integer timer) {
return Intent.sleep(createSleepIntent(createTimerTimeout(timer)));
}
public static SleepIntent createSleepIntent(Timer timer) {
return new SleepIntent(timer);
}
public static Timer createTimerTimeout(Integer timeout) {
return Timer.timeout(timeout);
}
}

View File

@ -0,0 +1,22 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.utils.extractors;
import com.rbkmoney.adapter.cashreg.spring.boot.starter.constant.OptionalField;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import java.util.Map;
import static java.lang.Integer.parseInt;
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class OptionsExtractors {
public static Integer extractPollingDelay(Map<String, String> options, int pollingDelay) {
return parseInt(options.getOrDefault(OptionalField.POLLING_DELAY.getField(), String.valueOf(pollingDelay)));
}
public static Integer extractMaxTimePolling(Map<String, String> options, int maxTimePolling) {
return Integer.parseInt(options.getOrDefault(OptionalField.MAX_TIME_POLLING.getField(), String.valueOf(maxTimePolling)));
}
}

View File

@ -0,0 +1,31 @@
package com.rbkmoney.adapter.cashreg.spring.boot.starter.utils.extractors;
import com.rbkmoney.damsel.cashreg.provider.CashRegContext;
import com.rbkmoney.damsel.cashreg.type.Type;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class TypeExtractor {
private static final String UNKNOWN_TYPE = "unknown_type";
public static String extractCashRegType(CashRegContext context) {
return extractCashRegType(context.getSession().getType());
}
public static String extractCashRegType(Type type) {
String state = UNKNOWN_TYPE;
if (type.isSetCredit()) {
state = Type._Fields.CREDIT.getFieldName();
} else if (type.isSetDebit()) {
state = Type._Fields.DEBIT.getFieldName();
} else if (type.isSetRefundCredit()) {
state = Type._Fields.REFUND_CREDIT.getFieldName();
} else if (type.isSetRefundDebit()) {
state = Type._Fields.REFUND_DEBIT.getFieldName();
}
return state.toUpperCase();
}
}

View File

@ -0,0 +1,5 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.rbkmoney.adapter.cashreg.spring.boot.starter.config.ErrorMappingConfiguration,\
com.rbkmoney.adapter.cashreg.spring.boot.starter.config.properties.AdapterProperties,\
com.rbkmoney.adapter.cashreg.spring.boot.starter.config.properties.TimerProperties,\
com.rbkmoney.adapter.cashreg.spring.boot.starter.config.ConverterIpConfiguration

View File

@ -0,0 +1,8 @@
[
{
"code":"unknown",
"description":"unknown",
"regexp":".*",
"mapping":"authorization_failed:unknown"
}
]