public static StateEvaluationResult ClearSelectedPaymentMethod(StateMachineContext context, StateEvaluationResult previousResult) { // Copy everything but the selected payment method return(new StateEvaluationResult( state: previousResult.State, checkoutStageContext: previousResult.CheckoutStageContext, selections: new CheckoutSelectionContext( selectedPaymentMethod: null, selectedBillingAddress: context.Selections.SelectedBillingAddress, selectedShippingAddress: context.Selections.SelectedShippingAddress, selectedShippingMethodId: context.Selections.SelectedShippingMethodId, creditCard: context.Selections.CreditCard, eCheck: context.Selections.ECheck, payPalExpress: context.Selections.PayPalExpress, amazonPayments: context.Selections.AmazonPayments, purchaseOrder: context.Selections.PurchaseOrder, acceptJsDetailsCreditCard: context.Selections.AcceptJsDetailsCreditCard, braintree: context.Selections.Braintree, sagePayPi: context.Selections.SagePayPi, termsAndConditionsAccepted: context.Selections.TermsAndConditionsAccepted, over13Checked: context.Selections.Over13Checked, email: context.Selections.Email))); }
StateEvaluationResult EvaluateStateMachine(StateMachineContext context) { // Set up the initial state var previousResult = new StateEvaluationResult( state: CheckoutState.Start, checkoutStageContext: new CheckoutStageContext( account: new CheckoutStageStatus( required: Guards.CustomerAccountRequired(context), available: null, fulfilled: null, disabled: null), paymentMethod: new CheckoutStageStatus( required: Guards.PaymentMethodRequired(context), available: Guards.PaymentMethodPresent(context), fulfilled: null, disabled: null), billingAddress: new CheckoutStageStatus( required: Guards.BillingAddressRequired(context), available: Guards.BillingAddressPresent(context), fulfilled: null, disabled: null), shippingAddress: new CheckoutStageStatus( required: Guards.ShippingAddressRequired(context), available: Guards.ShippingAddressPresent(context), fulfilled: null, disabled: !Guards.AllowShipToDifferentThanBillTo(context) || Guards.SkipShippingOnCheckout(context)), shippingMethod: new CheckoutStageStatus( required: Guards.ShippingMethodRequired(context), available: Guards.ShippingMethodPresent(context), fulfilled: null, disabled: Guards.SkipShippingOnCheckout(context)), giftCardSetup: new CheckoutStageStatus( required: Guards.CartContainsGiftCard(context), available: null, fulfilled: Guards.GiftCardSetupComplete(context), disabled: null), placeOrderButton: new CheckoutStageStatus( required: null, available: null, fulfilled: true, disabled: null)), selections: context.Selections); // Loop until we find an exit condition while (true) { // Find a transition from the current state where all guards pass var passedTransition = StateMachine.ContainsKey(previousResult.State) ? StateMachine[previousResult.State] .Where(transition => transition .Guards .Select(guard => guard(context)) .All(guardResult => guardResult == true)) .FirstOrDefault() : null; // If there's nothing to transition to, we've hit a terminal state and need to return if (passedTransition == null) { return(previousResult); } // Build up the next state var currentResult = new StateEvaluationResult( state: passedTransition.Target, checkoutStageContext: previousResult.CheckoutStageContext, selections: previousResult.Selections); // Run any triggers on the target state foreach (var trigger in passedTransition.Triggers) { currentResult = trigger(context, currentResult); } // If we're just looping back to the same state or we've hit the final state, we're done if (currentResult.State == previousResult.State || currentResult.State == CheckoutState.Valid) { return(currentResult); } // Set up the current state as the previous state and loop previousResult = currentResult; } }