Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
psemenkov 2022-12-14 14:24:23 +03:00
commit 8d2881c3eb
10 changed files with 283 additions and 187 deletions

View file

@ -1,28 +1,39 @@
package ru.spcex.clearing.backendapi.controller.queue.company;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import ru.clearing.classes.statics.data.profile.ProfileDocument;
import ru.spcex.clearing.backendapi.controller.queue.AbstractQueueController;
import ru.spcex.clearing.backendapi.controller.request.cud.company.ProfileDocumentNewAction;
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse;
import ru.spcex.clearing.backendapi.controller.response.entity.CommonGetAllResponse;
import ru.spcex.clearing.backendapi.service.IOperator;
import ru.spcex.clearing.backendapi.service.IStateLoader;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@Controller
@RequestMapping("/profile-documents")
public class ProfileDocumentController {
public class ProfileDocumentController extends AbstractQueueController {
private final IStateLoader stateLoader;
@Autowired
public ProfileDocumentController(IStateLoader stateLoader) {
public ProfileDocumentController(IStateLoader stateLoader, IOperator operator) {
super(operator);
this.stateLoader = stateLoader;
}
@ -36,4 +47,14 @@ public class ProfileDocumentController {
response.fromEntity(all);
return response;
}
@ApiOperation(value = "new profile document.")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = CudResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public CudResponse add(
@ApiParam(value = "Параметры команды в JSON формате.", required = true)
@RequestBody ProfileDocumentNewAction profileDocumentNewAction) throws ExecutionException, InterruptedException {
return processRequest(Consts.DESTINATION_PROFILE_DOCUMENT_NEW, profileDocumentNewAction);
}
}

View file

@ -0,0 +1,82 @@
package ru.spcex.clearing.backendapi.controller.request.cud.company;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.swagger.annotations.ApiModelProperty;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.company.ProfileDocumentNewRequest;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.LocalDateDeserializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
import java.time.LocalDate;
public class ProfileDocumentNewAction implements IAction<ProfileDocumentNewRequest> {
@ApiModelProperty(value = "Идентификатор Компании", example = "123")
@JsonProperty
private Long companyId;
@ApiModelProperty(value = "Идентификатор типа документа", example = "ABCD")
@JsonProperty
private String documentType;
@ApiModelProperty(value = "Дата выдачи", example = "2022-12-25")
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
private LocalDate issueDate;
@ApiModelProperty(value = "Место выдачи", example = "Example string")
@JsonProperty
private String issuePlace;
@ApiModelProperty(value = "Кем выдан", example = "Example string")
@JsonProperty
private String issuer;
@ApiModelProperty(value = "Код выдавшего органа", example = "Example string")
@JsonProperty
private String issuerCode;
@ApiModelProperty(value = "Наименование", example = "Example string")
@JsonProperty
private String name;
@ApiModelProperty(value = "Номер", example = "Example string")
@JsonProperty
private String number;
@ApiModelProperty(value = "Место", example = "Example string")
@JsonProperty
private String place;
@ApiModelProperty(value = "Дата начала срока действия", example = "2022-12-25")
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
private LocalDate validFromDate;
@ApiModelProperty(value = "Дата окончания срока действия", example = "2022-12-25")
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
private LocalDate validToDate;
@ApiModelProperty(value = "Ссылка на документ", example = "Example string")
@JsonProperty
private String link;
@Override
public ProfileDocumentNewRequest toRequest() {
ProfileDocumentNewRequest request = new ProfileDocumentNewRequest();
request.setCompanyId(this.companyId);
request.setDocumentType(this.documentType);
request.setIssueDate(this.issueDate);
request.setIssuePlace(this.issuePlace);
request.setIssuer(this.issuer);
request.setIssuerCode(this.issuerCode);
request.setName(this.name);
request.setNumber(this.number);
request.setPlace(this.place);
request.setValidFromDate(this.validFromDate);
request.setValidToDate(this.validToDate);
request.setLink(this.link);
return request;
}
@ApiModelProperty(hidden = true)
@Override
public ActionType getActionType() {
return ActionType.NEW;
}
}

View file

@ -1,81 +0,0 @@
package ru.spcex.clearing.scheduler.enums;
import java.io.Serializable;
import java.util.Objects;
/**
* Удобный интерфейс для enum при использовании TextErrorService.
*/
public interface IEnumWithLongValue extends Serializable {
/**
* Проверяет что среди данного набора Enum, присутствует элемент с данным id
* id может быть null
*/
static <T extends Enum<T> & IEnumWithLongValue> boolean contains(Long id, T... enumSet) {
for (T e : enumSet) {
if (Objects.equals(id, e.getId()))
return true;
}
return false;
}
static <T extends Enum<T> & IEnumWithLongValue> boolean contains(T e, T... enumSet) {
for (T enumEl : enumSet) {
if (enumEl.equals(e))
return true;
}
return false;
}
static <T extends Enum<T> & IEnumWithLongValue> Long[] toLongArray(T... enumSet) {
Long[] enumId = new Long[enumSet.length];
for (int i = 0; i < enumSet.length; i++)
enumId[i] = enumSet[i].getId();
return enumId;
}
/**
* Проверяет что среди всех Enum данного класса, присутствует элемент с данным id
* id может быть null
*/
static <T extends Enum<T> & IEnumWithLongValue> boolean contains(Class<T> enumClass, Long id) {
for (T e : enumClass.getEnumConstants()) {
if (Objects.equals(id, e.getId()))
return true;
}
return false;
}
/**
* Возвращает Enum по id, если в заданном классе такой определен
* id может быть null
*
* @return Enum если нашел, иначе <tt>null</tt>
*/
static <T extends Enum<T> & IEnumWithLongValue> T getEnumById(Class<T> enumClass, Long id) {
for (T e : enumClass.getEnumConstants()) {
if (Objects.equals(id, e.getId()))
return e;
}
return null;
}
static Long getIdOrNull(IEnumWithLongValue enumVal) {
return enumVal == null ? null : enumVal.getId();
}
/**
* errorCode
**/
Long getId();
default boolean equalsById(Long id) {
return id != null && getId().equals(id);
}
String elementName();
}

View file

@ -1,35 +0,0 @@
package ru.spcex.clearing.scheduler.enums;
import java.util.Objects;
public enum TaskStatuses {
ACTIVE("ACTV"),
BLOCKED("CNCL"),
CANCEL("BLKD");
private final String name;
TaskStatuses(String name) {
this.name = name;
}
public static TaskStatuses getEnumByName(String name) {
for (TaskStatuses e : TaskStatuses.values()) {
if (Objects.equals(name, e.name()))
return e;
}
return null;
}
public Boolean equalsByName(String name) {
return this.name.equalsIgnoreCase(name);
}
public String getName() {
return this.name;
}
public String elementName() {
return this.name();
}
}

View file

@ -1,45 +0,0 @@
package ru.spcex.clearing.scheduler.enums;
import java.util.Objects;
public enum Tasks {
GBAL("GBAL"),//Зачисление остатков
ABLK("ABLK"),//Блокировка счета
GALB("GALB"),//Запрос остатков по всем счетам
ADBL("ADBL"),//Дозачисление/списание остатков
CORD("CORD"),//Формирование сводного платежного поручения
CORC("CORC"),//Получение подтверждения переводов
GTRD("GTRD"),//Получение сделок из Торговой системы
GVER("GVER"),// Запуск сверки
GBLD("GBLD"),// Поступление средств
SCLR("SCLR"),// Запуск клиринговой сессии
SPRC("SPRC"),// Запуск преклиринга
SPOC("SPOC");// Запуск постклиринга
private String name;
Tasks(String name) {
this.name = name;
}
public static Tasks getEnumByName(String name) {
for (Tasks e : Tasks.values()) {
if (Objects.equals(name, e.name()))
return e;
}
return null;
}
public Boolean equalsByName(String name) {
return this.name.equalsIgnoreCase(name);
}
public String getName() {
return this.name;
}
public String elementName() {
return this.name();
}
}

View file

@ -11,8 +11,8 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.scheduling.TaskScheduler;
import ru.clearing.classes.statics.data.scheduler.PlannerAllToday;
import ru.spcex.clearing.scheduler.enums.TaskStatuses;
import ru.spcex.clearing.scheduler.enums.Tasks;
import ru.spcex.platform.enumeration.Status;
import ru.spcex.platform.enumeration.Task;
import java.time.LocalDate;
import java.time.LocalDateTime;
@ -27,7 +27,8 @@ import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;
import static ru.spcex.clearing.imdg.IMDGDistributedNames.Map_PlannerAllToday;
import static ru.spcex.clearing.scheduler.enums.TaskStatuses.*;
import static ru.spcex.platform.enumeration.Status.*;
import static ru.spcex.platform.utils.enumeration.IEnumKey.getEnumByKey;
/**
* Планировщик задач, расписание берёт из Hazelcast map.
@ -73,7 +74,7 @@ public abstract class TaskManager implements EntryAddedListener<Long, PlannerAll
public void entryAdded(EntryEvent<Long, PlannerAllToday> event) {
PlannerAllToday task = event.getValue();
Tasks taskType = Tasks.getEnumByName(task.getTask());
Task taskType = getEnumByKey(Task.class, task.getTask());
if (taskType == null) {
log.warn("Task skipped, {} task type not recognized", task.getTask());
return;
@ -89,23 +90,23 @@ public abstract class TaskManager implements EntryAddedListener<Long, PlannerAll
LocalTime oldTime = oldTask.getTaskTime();
// TaskStatuses oldStatus
//если таск относится к другому обработчику, пропускаем
if (!getTask().equalsByName(task.getTask()) && !getTask().equalsByName(oldTask.getTask())) {
if (!getTask().equalsByKey(task.getTask()) && !getTask().equalsByKey(oldTask.getTask())) {
return;
}
if (!Objects.equals(task.getTask(), oldTask.getTask())) {
throw new IllegalStateException("changed taskId for SchedulerAllToday in core");
}
if (ACTIVE.equalsByName(oldTask.getTaskStatus())) { //&& ACTIVE.equalsById(task.getTaskStatusId())
if (Active.equalsByKey(oldTask.getTaskStatus())) { //&& ACTIVE.equalsById(task.getTaskStatusId())
if (!removeTask(oldTime)) {
log.debug("cannot cancel task with type {}, time {}", getTask().name(), oldTime.toString());
} else {
log.debug("task with type {}, time {} execution cancelled, adding altered task...", getTask().name(), oldTime.toString());
}
processTask(task);
} else if (CANCEL.equalsByName(oldTask.getTaskStatus())) { //&& TaskStatuses.CANCEL.equalsById(task.getTaskStatusId())
} else if (Cancel.equalsByKey(oldTask.getTaskStatus())) { //&& TaskStatuses.CANCEL.equalsById(task.getTaskStatusId())
restorePreviouslyRemovedTask(oldTime, oldTask);
processTask(task);
} else if (BLOCKED.equalsByName(oldTask.getTaskStatus())) {
} else if (Blocked.equalsByKey(oldTask.getTaskStatus())) {
processTask(task);
}
}
@ -119,12 +120,12 @@ public abstract class TaskManager implements EntryAddedListener<Long, PlannerAll
}
LocalTime removedTaskTime = taskToRemove.getTaskTime();
if (ACTIVE.equalsByName(taskToRemove.getTaskStatus())) {
if (Active.equalsByKey(taskToRemove.getTaskStatus())) {
if (removeTask(removedTaskTime))
log.debug("task successfully canceled");
} else if (CANCEL.equalsByName(taskToRemove.getTaskStatus())) {
} else if (Cancel.equalsByKey(taskToRemove.getTaskStatus())) {
restorePreviouslyRemovedTask(removedTaskTime, taskToRemove);
} else if (BLOCKED.equalsByName(taskToRemove.getTaskStatus())) {
} else if (Blocked.equalsByKey(taskToRemove.getTaskStatus())) {
log.debug("BLOCKED task removed; do nothing");
}
}
@ -133,8 +134,8 @@ public abstract class TaskManager implements EntryAddedListener<Long, PlannerAll
ScheduledFuture cancelledFuture = scheduledJobs.get(oldTime);
if (cancelledFuture != null && cancelledFuture.isCancelled()) {
PlannerAllToday schedulerAllToday = new PlannerAllToday();
schedulerAllToday.setTask(getTask().getName());
schedulerAllToday.setTaskStatus(ACTIVE.getName());
schedulerAllToday.setTask(getTask().name());
schedulerAllToday.setTaskStatus(Active.name());
schedulerAllToday.setTaskTime(oldTask.getTaskTime());
log.debug("CANCEL task updated/removed; restoring previously cancelled task");
processTask(schedulerAllToday);
@ -145,7 +146,7 @@ public abstract class TaskManager implements EntryAddedListener<Long, PlannerAll
protected void updateScheduler() {
Collection<PlannerAllToday> schedulerAllTodays = plannerAllTodayMapStore.values();
Collection<PlannerAllToday> sortedSchedulers =
schedulerAllTodays.stream().sorted((o1, o2) -> (ACTIVE.equalsByName(o1.getTaskStatus()) && CANCEL.equalsByName(o2.getTaskStatus())) ? -1 : 0)
schedulerAllTodays.stream().sorted((o1, o2) -> (Active.equalsByKey(o1.getTaskStatus()) && Cancel.equalsByKey(o2.getTaskStatus())) ? -1 : 0)
.collect(Collectors.toCollection(ArrayList::new));
for (PlannerAllToday schedulerAllToday : sortedSchedulers) {
processTask(schedulerAllToday);
@ -155,8 +156,8 @@ public abstract class TaskManager implements EntryAddedListener<Long, PlannerAll
// --- Работа с задачами ---
private void processTask(PlannerAllToday task) {
LocalTime taskTime = task.getTaskTime();
Tasks taskType = Tasks.getEnumByName(task.getTask());
TaskStatuses taskStatus = TaskStatuses.getEnumByName(task.getTaskStatus());
Task taskType = getEnumByKey(Task.class, task.getTask());
Status taskStatus = getEnumByKey(Status.class, task.getTaskStatus());
if (taskStatus == null) throw new IllegalStateException("task status from core can't be null");
if (!getTask().equals(taskType)) {
log.debug("Task skipped - taskTime {}, is not of acceptable type {}", taskTime.toString(), taskType != null ? taskType.name() : "");
@ -166,19 +167,19 @@ public abstract class TaskManager implements EntryAddedListener<Long, PlannerAll
log.debug("Task skipped - taskTime {} is before now, taskType {} ok", taskTime, getTask().toString());
return;
}
if (taskStatus.equals(BLOCKED)) {
log.debug("Task skipped - timeTime {} with status {}", taskTime.toString(), BLOCKED.toString());
if (taskStatus.equals(Blocked)) {
log.debug("Task skipped - timeTime {} with status {}", taskTime.toString(), Blocked.toString());
return;
}
{
ScheduledFuture future = scheduledJobs.get(taskTime);
if (future != null) {
if (TaskStatuses.CANCEL.equals(taskStatus)) {
if (Cancel.equals(taskStatus)) {
//случай когда пришел cancel, пытаемся отменить зарегистрированный ранее таск
future.cancel(false);
log.debug("cancelling task time {}", taskTime);
return;
} else if (TaskStatuses.ACTIVE.equals(taskStatus)) {
} else if (Active.equals(taskStatus)) {
//случай когда пришел активный таск, и уже был на это время неотмененный
if (!future.isCancelled()) {
log.debug("such task time {} has already been registered", taskTime);
@ -187,7 +188,7 @@ public abstract class TaskManager implements EntryAddedListener<Long, PlannerAll
}
}
}
if (TaskStatuses.CANCEL.equals(taskStatus)) {
if (Cancel.equals(taskStatus)) {
log.debug("task type {} time {} with status CANCEL - no tasks to cancel found", taskType.name(), taskTime);
return;
}
@ -218,7 +219,7 @@ public abstract class TaskManager implements EntryAddedListener<Long, PlannerAll
*
* @return идентификатор для фильтра типов планировщика задачь. Планировать задачи только этого типа.
*/
protected abstract Tasks getTask();
protected abstract Task getTask();
protected abstract void doJob(PlannerAllToday taskInfo);
}

View file

@ -3,7 +3,9 @@ package ru.spcex.platform.enumeration;
import ru.spcex.platform.utils.enumeration.IEnumKey;
public enum Status implements IEnumKey {
Active("ACTV"), Blocked("BLKD");
Active("ACTV"),
Blocked("BLKD"),
Cancel("CNCL");
private final String key;

View file

@ -3,7 +3,19 @@ package ru.spcex.platform.enumeration;
import ru.spcex.platform.utils.enumeration.IEnumKey;
public enum Task implements IEnumKey {
createOrder("CORD"), createOrderConfirm("CORC"), getAllBalance("GALB");
accrualOfBalance("GBAL"),//Зачисление остатков
accountBlock("ABLK"),//Блокировка счета
additionOrDeleteOfBalance("ADBL"),//Дозачисление/списание остатков
getOfTrades("GTRD"),//Получение сделок из Торговой системы
getVerification("GVER"),// Запуск сверки
getBalance("GBLD"),// Поступление средств
startOfClearing("SCLR"),// Запуск клиринговой сессии
startOfPreClearing("SPRC"),// Запуск преклиринга
startPostClearing("SPOC"),// Запуск постклиринга
createOrder("CORD"),
createOrderConfirm("CORC"),
getAllBalance("GALB");
private final String key;

View file

@ -33,6 +33,7 @@ public interface Consts {
String DESTINATION_BANK_ACCOUNT_UPDATE = "bank-account-update";
String DESTINATION_BANK_ACCOUNT_NEW = "bank-account-new";
String DESTINATION_RELATION_UPDATE = "relation-update";
String DESTINATION_PROFILE_DOCUMENT_NEW = "profile-document-new";
String DESTINATION_SDF08_NEW = "s-df-08-new";
String DESTINATION_SDF02_NEW = "s-df-02-new";

View file

@ -0,0 +1,138 @@
package ru.spcex.clearing.platform.messaging.domain.cud.company;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import ru.spcex.clearing.platform.messaging.domain.json.deserialize.LocalDateDeserializer;
import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalDateSerializer;
import java.time.LocalDate;
public class ProfileDocumentNewRequest {
@JsonProperty
private Long companyId;
@JsonProperty
private String documentType;
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
private LocalDate issueDate;
@JsonProperty
private String issuePlace;
@JsonProperty
private String issuer;
@JsonProperty
private String issuerCode;
@JsonProperty
private String name;
@JsonProperty
private String number;
@JsonProperty
private String place;
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
private LocalDate validFromDate;
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonProperty
private LocalDate validToDate;
@JsonProperty
private String link;
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public String getDocumentType() {
return documentType;
}
public void setDocumentType(String documentType) {
this.documentType = documentType;
}
public LocalDate getIssueDate() {
return issueDate;
}
public void setIssueDate(LocalDate issueDate) {
this.issueDate = issueDate;
}
public String getIssuePlace() {
return issuePlace;
}
public void setIssuePlace(String issuePlace) {
this.issuePlace = issuePlace;
}
public String getIssuer() {
return issuer;
}
public void setIssuer(String issuer) {
this.issuer = issuer;
}
public String getIssuerCode() {
return issuerCode;
}
public void setIssuerCode(String issuerCode) {
this.issuerCode = issuerCode;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
public LocalDate getValidFromDate() {
return validFromDate;
}
public void setValidFromDate(LocalDate validFromDate) {
this.validFromDate = validFromDate;
}
public LocalDate getValidToDate() {
return validToDate;
}
public void setValidToDate(LocalDate validToDate) {
this.validToDate = validToDate;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
}