From 2110b2089e72342b305ba55443b2e59c90472826 Mon Sep 17 00:00:00 2001 From: etreschenkov Date: Thu, 3 Jul 2025 18:03:25 +0300 Subject: [PATCH] UnitedSession state machine config --- .../UnitedSessionStateMachineConfig.java | 269 ++++++++++++++++++ .../spcex/clearing/util/StateMachineUtil.java | 9 +- 2 files changed, 273 insertions(+), 5 deletions(-) create mode 100644 clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/state_machine_2/specific/UnitedSessionStateMachineConfig.java diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/state_machine_2/specific/UnitedSessionStateMachineConfig.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/state_machine_2/specific/UnitedSessionStateMachineConfig.java new file mode 100644 index 000000000..fc504582d --- /dev/null +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/state_machine_2/specific/UnitedSessionStateMachineConfig.java @@ -0,0 +1,269 @@ +package ru.spcex.clearing.config.state_machine_2.specific; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.function.Supplier; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.config.EnableStateMachineFactory; +import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.guard.Guard; +import org.springframework.statemachine.listener.StateMachineListenerAdapter; +import ru.clearing.classes.statics.data.execution.ExecutionFond; +import ru.clearing.classes.statics.data.misc.Session; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.session.stage.TaskType; +import ru.spcex.clearing.session.state.DataEnum; +import ru.spcex.clearing.session.state.SsnEvent; +import ru.spcex.clearing.session.state.action.AgainReviseStage3Action; +import ru.spcex.clearing.session.state.action.CompoundDealsPrepareAction; +import ru.spcex.clearing.session.state.action.CreateSessionAction; +import ru.spcex.clearing.session.state.action.DealsPrepareAction; +import ru.spcex.clearing.session.state.action.DiscardRegistriesAction; +import ru.spcex.clearing.session.state.action.FinishingSessionAction; +import ru.spcex.clearing.session.state.action.FormingPaymentInstructionAssetsAction; +import ru.spcex.clearing.session.state.action.InclusionToPoolAction; +import ru.spcex.clearing.session.state.action.InspectionObligationsV2Action; +import ru.spcex.clearing.session.state.action.ObligationAdmissionAction; +import ru.spcex.clearing.session.state.action.RequirementAndObligationCreationAction; +import ru.spcex.clearing.session.state.action.ReviseStage1Action; +import ru.spcex.clearing.session.state.action.SaveRegistriesAndContinueAction; +import ru.spcex.clearing.session.state.action.Sdf56Action; +import ru.spcex.clearing.session.state.guard.PaymentsWereCreatedGuard; +import ru.spcex.clearing.session.state.guard.PaymentsWereNotCreatedGuard; +import ru.spcex.clearing.session.state.guard.SdfGuard; +import ru.spcex.clearing.session.state.guard.SdfGuardExtractorAfterAgainRevise; +import ru.spcex.clearing.session.state.guard.SdfGuardExtractorAfterAssets; +import ru.spcex.clearing.session.state.guard.StashedRegistriesPresentGuard; +import ru.spcex.clearing.session.state.listener.MachineMonitoringListener; +import static ru.spcex.clearing.util.StateMachineUtil.*; +import ru.spcex.platform.classes.base.interfaces.ExecutionType; +import ru.spcex.platform.enumeration.Section; +import ru.spcex.platform.enumeration.SessionType; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; + +@Configuration("intermediateMkrSessionStateMachineFactoryConfig") +@EnableStateMachineFactory(name = "UNIT") +public class UnitedSessionStateMachineConfig + extends EnumStateMachineConfigurerAdapter { + + private final Imdg sessionImdg; + private final Sdf56Action sendSdf56Action; + private final ReviseStage1Action reviseStage1Action; + private final DealsPrepareAction dealsPrepareCurrency; + private final DealsPrepareAction dealsPrepareTRDT; + private final DealsPrepareAction dealsPrepareFinal; + private final RequirementAndObligationCreationAction reqAndOblAction; + private final ObligationAdmissionAction obligationAdmissionAction; + private final InclusionToPoolAction inclusionToPoolAction; + private final InspectionObligationsV2Action inspectionObligationsV2Action; + private final FormingPaymentInstructionAssetsAction formingPaymentInstructionAssetsAction; + private final AgainReviseStage3Action againRevise; + private final SaveRegistriesAndContinueAction obligationAdmissionContinueAction; + private final FinishingSessionAction finishingSessionAction; + private final DiscardRegistriesAction discardOblAdmStash = + new DiscardRegistriesAction(DataEnum.obligationAdmissionStashedRgs); + private final StashedRegistriesPresentGuard oblAdmGuard = new StashedRegistriesPresentGuard( + DataEnum.obligationAdmissionStashedRgs + ); + private final Guard reviseSuccessGuard = guardCheckCtxForFlag(DataEnum.againReviseSuccess); + private final SessionType SESSION_TYPE = SessionType.UNIT; + + public UnitedSessionStateMachineConfig(ImdgProvider imdgProvider, + Sdf56Action sendSdf56Action, + ReviseStage1Action reviseStage1Action, + ObjectFactory dealsPrepareAction, + @Qualifier("requirementAndObligationCreationAction") + RequirementAndObligationCreationAction reqAndOblAction, + ObligationAdmissionAction obligationAdmissionAction, + InclusionToPoolAction inclusionToPoolAction, + InspectionObligationsV2Action inspectionObligationsV2Action, + FormingPaymentInstructionAssetsAction formingPaymentInstructionAssetsAction, + AgainReviseStage3Action againRevise, + SaveRegistriesAndContinueAction obligationAdmissionContinueAction, + FinishingSessionAction finishingSessionAction, + @Qualifier("marketCodesForCurr") Supplier> marketCodesCurr, + @Qualifier("marketCodesForT0") Supplier> marketCodesTrdt) { + this.sessionImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Session, Session.class); + this.sendSdf56Action = sendSdf56Action; + this.reviseStage1Action = reviseStage1Action; + this.dealsPrepareCurrency = dealsPrepareAction.getObject(); + this.dealsPrepareTRDT = dealsPrepareAction.getObject(); + this.dealsPrepareFinal = dealsPrepareAction.getObject(); + this.reqAndOblAction = reqAndOblAction; + this.obligationAdmissionAction = obligationAdmissionAction; + this.inclusionToPoolAction = inclusionToPoolAction; + this.inspectionObligationsV2Action = inspectionObligationsV2Action; + this.formingPaymentInstructionAssetsAction = formingPaymentInstructionAssetsAction; + this.againRevise = againRevise; + this.obligationAdmissionContinueAction = obligationAdmissionContinueAction; + this.finishingSessionAction = finishingSessionAction; + + { + Imdg executionFondImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ExecutionFond, ExecutionFond.class); + dealsPrepareCurrency.searchForExecutions(ExecutionType.ExecutionCurrency); + ImdgPredicateBuilder pb = executionFondImdg.predicateBuilder(); + dealsPrepareCurrency.addExecutionCurrencyCondition(pb.regex("settlementCode", "^T0.*$")); + dealsPrepareCurrency.addExecutionCurrencyCondition(pb.in("market", marketCodesCurr.get().toArray(new String[0]))); + dealsPrepareTRDT.searchForExecutions(ExecutionType.ExecutionFond); + ImdgPredicateBuilder execFondPb = executionFondImdg.predicateBuilder(); + dealsPrepareTRDT.addExecutionFondCondition(execFondPb.regex("settlementCode", "^T0.*$")); + dealsPrepareTRDT.addExecutionFondCondition(execFondPb.in("market", marketCodesTrdt.get().toArray(new String[0]))); + + dealsPrepareFinal.searchForExecutions(ExecutionType.ExecutionDeposit); + dealsPrepareFinal.addExecutionDepositCondition(pb.regex("firstLegSettlementCode", "^T0.*$")); + + this.finishingSessionAction.setPr("1"); + } + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(TaskType.StartRevise, chain( + new CreateSessionAction(sessionImdg, SessionType.UNIT, Section.MULT), + sendSdf56Action)) + .states(new HashSet<>(Arrays.asList( + TaskType.StartRevise, + TaskType.StartRevisePart1, + TaskType.DealsPrepare, + TaskType.RequirementsAndObligationsCreate, + TaskType.ObligationsAdmission, + TaskType.InclusionToPool, + TaskType.InspectionObligations, + TaskType.FormingPaymentInstruction, + TaskType.FinishingSession, + TaskType.EndStageNotification, + TaskType.PSEUDO_waitSdfAfterPaymentInstructions, + TaskType.PSEUDO_waitAfterObligationAdmissionError, + TaskType.EndStageNotification, + TaskType.AgainRevise, + TaskType.PSEUDO_waitSdfAfterAgainRevise + ))) + .end(TaskType.EndStageNotification); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .event(SsnEvent.SDF_57) + .source(TaskType.StartRevise).target(TaskType.StartRevisePart1) + .action(reviseStage1Action) + .and() + .withExternal() + .source(TaskType.StartRevisePart1).target(TaskType.DealsPrepare) + .action( + chain( + dealsPrepareCurrency, new CompoundDealsPrepareAction(ExecutionType.ExecutionCurrency), + dealsPrepareFinal, new CompoundDealsPrepareAction(ExecutionType.ExecutionDeposit), + dealsPrepareTRDT, new CompoundDealsPrepareAction(ExecutionType.ExecutionFond)) + ) + .and() + .withExternal() + .source(TaskType.DealsPrepare).target(TaskType.RequirementsAndObligationsCreate) + .action(reqAndOblAction) + .and() + .withExternal() + .source(TaskType.RequirementsAndObligationsCreate).target(TaskType.ObligationsAdmission) + .action(obligationAdmissionAction) + .and() + .withExternal() + .source(TaskType.InclusionToPool).target(TaskType.InspectionObligations) + .action(inspectionObligationsV2Action) + .and() + .withExternal() + .source(TaskType.InspectionObligations).target(TaskType.FormingPaymentInstruction) + .action(formingPaymentInstructionAssetsAction) + .and() + .withExternal() + .source(TaskType.PSEUDO_waitSdfAfterPaymentInstructions) + .target(TaskType.AgainRevise) + .guard(new SdfGuard(SdfGuardExtractorAfterAssets.instance)) + .action(againRevise) + .and() + .withExternal() + .source(TaskType.PSEUDO_waitSdfAfterAgainRevise) + .target(TaskType.AgainRevise) + .guard(new SdfGuard(SdfGuardExtractorAfterAgainRevise.instance)) + .action(againRevise); + sourceObligationAdmission(transitions); + sourcePseudoAfterOAError(transitions); + sourceFormingPaymentInstruction(transitions); + sourceAgainRevise(transitions); + } + + private void sourceObligationAdmission(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TaskType.ObligationsAdmission) + .target(TaskType.PSEUDO_waitAfterObligationAdmissionError) + .guard(oblAdmGuard) + .and() + .withExternal() + .source(TaskType.ObligationsAdmission).target(TaskType.InclusionToPool) + .guard(invert(oblAdmGuard)) + .action(chain(obligationAdmissionContinueAction, inclusionToPoolAction)); + } + + private void sourcePseudoAfterOAError(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TaskType.PSEUDO_waitAfterObligationAdmissionError).target(TaskType.InclusionToPool) + .action(chain(obligationAdmissionContinueAction, inclusionToPoolAction)) + .event(SsnEvent.CONTINUE) + .and() + .withExternal() + .source(TaskType.PSEUDO_waitAfterObligationAdmissionError).target(TaskType.ObligationsAdmission) + .action(chain(discardOblAdmStash, obligationAdmissionAction)) + .event(SsnEvent.REPEAT); + } + + private void sourceFormingPaymentInstruction(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + //если не создалось paymentInstruction'ов + .withExternal() + .source(TaskType.FormingPaymentInstruction) + .target(TaskType.AgainRevise) + .guard(PaymentsWereNotCreatedGuard.instance) + .action(againRevise) + .and() + //если создались paymentInstruction, переходим в режим ожидания + .withExternal() + .source(TaskType.FormingPaymentInstruction) + .target(TaskType.PSEUDO_waitSdfAfterPaymentInstructions) + .guard(PaymentsWereCreatedGuard.instance); + } + + private void sourceAgainRevise(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(TaskType.AgainRevise) + .target(TaskType.FinishingSession) + .action(finishingSessionAction) + .guard(reviseSuccessGuard) + .and() + .withExternal() + .source(TaskType.AgainRevise) + .target(TaskType.PSEUDO_waitSdfAfterAgainRevise) + .guard(invert(reviseSuccessGuard)); + } + + @Override + public void configure(StateMachineConfigurationConfigurer config) throws Exception { + StateMachineListenerAdapter loggingChangeStateListener + = new MachineMonitoringListener(SESSION_TYPE.getKey()); + config + .withConfiguration() + .machineId(SESSION_TYPE.getKey()) + .listener(loggingChangeStateListener); + } +} diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/util/StateMachineUtil.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/util/StateMachineUtil.java index 51dc8b7da..dd7a17a52 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/util/StateMachineUtil.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/util/StateMachineUtil.java @@ -1,5 +1,6 @@ package ru.spcex.clearing.util; +import java.util.List; import org.springframework.statemachine.StateContext; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.action.Action; @@ -24,11 +25,9 @@ public class StateMachineUtil { return context -> !guard.evaluate(context); } - public static Action chain(Action a, Action b) { - return context -> { - a.execute(context); - b.execute(context); - }; + @SafeVarargs + public static Action chain(Action... a) { + return context -> List.of(a).forEach(action -> action.execute(context)); }