diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/config/ValidationConfig.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/config/ValidationConfig.java index 225b19024..89f76c261 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/config/ValidationConfig.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/config/ValidationConfig.java @@ -49,6 +49,7 @@ import static ru.spcex.platform.imdg.api.predicate.specific.IdEqualPredicate.byI import ru.spcex.platform.imdg.api.predicate.specific.SecuritySelector; import ru.spcex.platform.imdg.validation.ImdgValidationContext; import ru.spcex.platform.imdg.validation.LogPrefixId; +import ru.spcex.platform.imdg.validation.rule.CollectionByPredicate; import ru.spcex.platform.imdg.validation.rule.PresentById; import ru.spcex.platform.imdg.validation.rule.PresentByPredicate; import ru.spcex.platform.utils.enumeration.EnumMessage; @@ -455,7 +456,7 @@ public class ValidationConfig { .store(OrderCurrencyValidationStored.TCR) .build(); - var counterOrderPresent = PresentByPredicate + var counterOrderPresentV2 = CollectionByPredicate .builder(r -> { OrderCurrency oc = ctx.getStoredObject(OrderCurrencyValidationStored.OrderCurrency); ImdgPredicateBuilder pb = orderCurrencyImdg.predicateBuilder(); @@ -470,6 +471,7 @@ public class ValidationConfig { .mapName(IMDGDistributedNames.Map_OrderCurrency) .errorProvider(r -> recordNotFound("counter OrderCurrency")) .store(OrderCurrencyValidationStored.CounterOrderCurrency) + .greaterOrEquals(1) .build(); //fixme проверить что tcr.getCompanyId() = companyId из запроса? @@ -481,7 +483,7 @@ public class ValidationConfig { OrderCurrencyCompanyNotChanged.INSTANCE, //OrderCurrencyByCompanyAndTcrAlreadyPresent.getInstance(OrderCompanyUpdateRequest.class), OrderCurrencyPLBLCheck.INSTANCE, - counterOrderPresent); + counterOrderPresentV2); }; } @@ -502,7 +504,7 @@ public class ValidationConfig { .store(OrderCurrencyValidationStored.OrderCurrency) .build(); - var counterOrderPresent = PresentByPredicate + var counterOrderPresentV2 = CollectionByPredicate .builder(r -> { OrderCurrency oc = ctx.getStoredObject(OrderCurrencyValidationStored.OrderCurrency); ImdgPredicateBuilder pb = orderCurrencyImdg.predicateBuilder(); @@ -517,11 +519,12 @@ public class ValidationConfig { .mapName(IMDGDistributedNames.Map_OrderCurrency) .errorProvider(r -> recordNotFound("counter OrderCurrency")) .store(OrderCurrencyValidationStored.CounterOrderCurrency) + .greaterOrEquals(1) .build(); return new ValidatorImpl<>(ctx, orderCurrencyPresent, - counterOrderPresent); + counterOrderPresentV2); }; } diff --git a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java index 6862a3e59..750e5278c 100644 --- a/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java +++ b/clearing-parent/default-management/src/main/java/ru/spcex/clearing/dflt/management/listener/OrderCurrencyListener.java @@ -4,8 +4,10 @@ import java.math.BigDecimal; import java.time.Instant; import java.time.LocalDate; import java.util.Arrays; +import java.util.Collection; import java.util.Optional; import java.util.function.Function; +import java.util.stream.Collectors; import org.apache.kafka.clients.consumer.Consumer; import org.apache.kafka.clients.producer.Producer; import org.slf4j.Logger; @@ -362,7 +364,7 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing OrderCurrency order = validator.getStored(OrderCurrencyValidationStored.OrderCurrency); Company company = validator.getStored(OrderCurrencyValidationStored.Company); TradingClearingRegistry tcr = validator.getStored(OrderCurrencyValidationStored.TCR); - OrderCurrency counterOrder = validator.getStored(OrderCurrencyValidationStored.CounterOrderCurrency); + Collection counterOrders = validator.getStored(OrderCurrencyValidationStored.CounterOrderCurrency); order.setCompanyId(payload.getCompanyId()); order.setTradingClearingRegistryId(payload.getTradingClearingRegistryId()); @@ -371,14 +373,18 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing order.setTradingCode(company.getTradingCode()); order.setUpdated(now); - counterOrder.setCounterPartyId(payload.getCompanyId()); - counterOrder.setCounterTradingCode(company.getTradingCode()); - counterOrder.setQuantityLot(new BigDecimal(payload.getQuantityLot())); - counterOrder.setUpdated(now); - - log.info("updating OrderCurrency[{}, {}]", order.getId(), counterOrder.getId()); + log.info("updating OrderCurrency[{}, {}]", order.getId(), + counterOrders.stream().map(OrderCurrency::getId).map(Object::toString).collect(Collectors.joining(","))); orderCurrencyImdg.update(order); - orderCurrencyImdg.update(counterOrder); + + counterOrders.forEach(counterOrder -> { + counterOrder.setCounterPartyId(payload.getCompanyId()); + counterOrder.setCounterTradingCode(company.getTradingCode()); + counterOrder.setQuantityLot(new BigDecimal(payload.getQuantityLot())); + counterOrder.setUpdated(now); + orderCurrencyImdg.update(counterOrder); + } + ); return null; } @@ -390,11 +396,12 @@ public class OrderCurrencyListener extends QueueConsumer implements Initializing return new RequestInfoUpdate(req.getId(), Status.Error, msgResolver.resolve(error.get())); } OrderCurrency order = validator.getStored(OrderCurrencyValidationStored.OrderCurrency); - OrderCurrency counterOrder = validator.getStored(OrderCurrencyValidationStored.CounterOrderCurrency); + Collection counterOrders = validator.getStored(OrderCurrencyValidationStored.CounterOrderCurrency); - log.info("deleting OrderCurrency[{}, {}]", order.getId(), counterOrder.getId()); + log.info("deleting OrderCurrency[{}, {}]", order.getId(), + counterOrders.stream().map(OrderCurrency::getId).map(Object::toString).collect(Collectors.joining(","))); reject(order); - reject(counterOrder); + counterOrders.forEach(this::reject); return null; } diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/validation/rule/CollectionByPredicate.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/validation/rule/CollectionByPredicate.java new file mode 100644 index 000000000..ad33359b3 --- /dev/null +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/validation/rule/CollectionByPredicate.java @@ -0,0 +1,177 @@ +package ru.spcex.platform.imdg.validation.rule; + +import java.util.Collection; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicate; +import ru.spcex.platform.imdg.validation.ImdgValidationContext; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.validation.IValidationRule; + +public class CollectionByPredicate implements IValidationRule> { + private static final Logger log = LoggerFactory.getLogger(CollectionByPredicate.class); + + private final String mapName; + private final Function errorProvider; + private final Function predicateProvider; + private final Enum storeEnabled; + private Integer precise; + private Integer min; + private Integer max; + + private CollectionByPredicate( + String mapName, + Function predicateProvider, + Function errorProvider, + Enum storeEnabled + ) { + this.mapName = mapName; + this.errorProvider = errorProvider; + this.storeEnabled = storeEnabled; + this.predicateProvider = predicateProvider; + } + + public void setPrecise(Integer precise) { + this.precise = precise; + } + + public void setMin(Integer min) { + this.min = min; + } + + public void setMax(Integer max) { + this.max = max; + } + + public static PredicateStep builder(Function predicateProvider) { + return new Builder<>(predicateProvider); + } + + @Override + public Optional validate(ImdgValidationContext context) { + T validatedObject = context.getValidatedObject(); + Imdg targetMap = context.obtainMap(mapName, SpcexObjectBase.class); + + ImdgPredicate predicate = predicateProvider.apply(validatedObject); + Collection obj = targetMap.getCollectionObjectsByPredicate(predicate); + String specificMsg = "[too many...]"; + if (obj.size() <= 20) { + specificMsg = obj + .stream() + .map(SpcexObjectBase::getId) + .map(Object::toString) + .collect(Collectors.joining(",", "[", "]")); + } + log.debug("objects found by predicate [{}]: size {}, ids {}", predicate, obj.size(), specificMsg); + + if (precise != null && obj.size() != precise) { + log.debug("predicate: {}; expected size: {}, actual: {}", predicate, precise, obj.size()); + return Optional.of(errorProvider.apply(validatedObject)); + } + + if (max != null && obj.size() > max) { + log.debug("predicate: {}; more objects found ({}) than expected ({})", predicate, obj.size(), max); + return Optional.of(errorProvider.apply(validatedObject)); + } + + if (min != null && obj.size() < min) { + log.debug("predicate: {}; fewer objects were found ({}) than expected ({}) ", predicate, obj.size(), min); + return Optional.of(errorProvider.apply(validatedObject)); + } + + if (storeEnabled != null) { + context.storeObject(storeEnabled, obj); + } + + return Optional.empty(); + } + + public interface PredicateStep { + MapStep mapName(String mapName); + } + + public interface MapStep { + OptionsStep errorProvider(Function errorProvider); + } + + public interface OptionsStep { + OptionsStep store(Enum storeEnabled); + OptionsStep precise(int number); + OptionsStep greaterOrEquals(int number); + OptionsStep lessThanOrEquals(int number); + CollectionByPredicate build(); + } + + + private static class Builder + implements PredicateStep, MapStep, OptionsStep { + + private final Function predicateProvider; + private String mapName; + private Function errorProvider; + private Enum storeEnabled; + private int precise; + private int min; + private int max; + + + private Builder(Function predicateProvider) { + this.predicateProvider = predicateProvider; + } + + @Override + public MapStep mapName(String mapName) { + this.mapName = mapName; + return this; + } + + @Override + public OptionsStep errorProvider(Function errorProvider) { + this.errorProvider = errorProvider; + return this; + } + + @Override + public OptionsStep store(Enum storeEnabled) { + this.storeEnabled = storeEnabled; + return this; + } + + @Override + public OptionsStep precise(int number) { + this.precise = number; + return this; + } + + @Override + public OptionsStep greaterOrEquals(int number) { + this.min = number; + return this; + } + + @Override + public OptionsStep lessThanOrEquals(int number) { + this.max = number; + return this; + } + + @Override + public CollectionByPredicate build() { + CollectionByPredicate rule = new CollectionByPredicate<>( + mapName, + predicateProvider, + errorProvider, + storeEnabled + ); + rule.setMax(max); + rule.setMin(min); + rule.setPrecise(precise); + return rule; + } + } +} \ No newline at end of file