public string Get3DsForm(AdditionalAuth auth, string key = "default")
        {
            var parameters = new Dictionary <string, string> {
                { "acs_url", auth.AcsUrl }, { "term_url", "" /*todo add actual home url*/ }, { "md", auth.Md }, { "pa_req", auth.PaReq }
            };
            var form = _formFactory.Get3DsForm(key);

            return(Proceed(form, parameters));
        }
        private ProceedStatus InnerSimpleOperation(Merchant merchant, Session session, PaymentData paymentData, OperationType operationType, long amount)
        {
            var actualAmount  = amount != 0 ? amount : session.Amount;
            var operationList = _dbContext.Operation.OrderByDescending(x => x.Id).Where(x => x.SessionId == session.Id).ToList();

            if (operationList.Count == 0 && session.ExpireTime < DateTime.Now)
            {
                return new ProceedStatus {
                           InnerError = InnerError.SessionExpired
                }
            }
            ;
            var lastOperation = operationList.OrderByDescending(x => x.Id)
                                .FirstOrDefault(x => x.OperationStatus == OperationStatus.Success);

            CheckPossibility(session, operationList, operationType, actualAmount);
            var terminal = _terminalSelector.Select(merchant, operationList, operationType, amount);

            var processing = _processingFactory.GetProcessing(terminal.Id, _dbContext);

            var operation = new Operation
            {
                SessionId       = session.Id,
                OperationStatus = OperationStatus.Created,
                TerminalId      = terminal.Id,
                Amount          = actualAmount,
                InvolvedAmount  = 0,
                ExternalId      = IdHelper.GetOperationId(),
                OperationType   = operationType,
                CreateDate      = DateTime.UtcNow,
                ExpireMonth     = paymentData?.ExpireMonth ?? lastOperation?.ExpireMonth,
                ExpireYear      = paymentData?.ExpireYear ?? lastOperation?.ExpireYear,
                MaskedPan       = paymentData != null?MaskHelper.MaskPan(paymentData.Pan) : lastOperation?.MaskedPan
            };

            _dbContext.Operation.Add(operation);
            _dbContext.SaveChanges();
            ProceedStatus response;

            try
            {
                IProcessingResponse processingResponse;

                switch (operationType)
                {
                case OperationType.Credit:
                    if (!processing.Properties.AllowCredit)
                    {
                        throw new OuterException(InnerError.OperationNotSupportedByProcessing);
                    }
                    processingResponse = processing.Credit(session, operation, terminal, paymentData);
                    break;

                case OperationType.Deposit:
                    if (!processing.Properties.AllowDebit)
                    {
                        throw new OuterException(InnerError.OperationNotSupportedByProcessing);
                    }
                    processingResponse = processing.Debit(session, operation, terminal, paymentData);
                    break;

                case OperationType.Hold:
                    if (!processing.Properties.AllowHold)
                    {
                        throw new OuterException(InnerError.OperationNotSupportedByProcessing);
                    }
                    processingResponse = processing.Hold(session, operation, terminal, paymentData);
                    break;

                case OperationType.Charge:
                    if (!processing.Properties.AllowHold || actualAmount != session.Amount && !processing.Properties.AllowPartialCharge)
                    {
                        throw new OuterException(InnerError.OperationNotSupportedByProcessing);
                    }
                    processingResponse = processing.Charge(session, operation, terminal);
                    break;

                default:
                    throw new OuterException(InnerError.NotImplemented);
                }

                operation.ProcessingOrderId = processingResponse.ProcessingOrderId;
                operation.OperationStatus   = processingResponse.Status;
                AdditionalAuth auth = null;
                switch (processingResponse.Status)
                {
                case OperationStatus.Success:
                    operation.InvolvedAmount = operation.Amount;
                    break;

                case OperationStatus.AdditionalAuth:
                    auth = processingResponse.AuthData;
                    var operation3ds = new Operation3ds
                    {
                        LocalMd         = IdHelper.GetMd(),
                        OperationId     = operation.Id,
                        RemoteMd        = auth.Md,
                        SaveCredentials = processingResponse.SavePaymentData
                    };
                    _dbContext.Add(operation3ds);
                    auth.Md = operation3ds.LocalMd;
                    if (operation3ds.SaveCredentials)
                    {
                        _remoteContainer.Set(operation3ds.LocalMd, paymentData);
                    }
                    break;
                }
                response = new ProceedStatus {
                    OperationStatus = operation.OperationStatus, AdditionalAuth = auth
                };
            }
            catch (Exception exc)
            {
                _logger.LogError(exc.Message);
                operation.OperationStatus = OperationStatus.Error;
                response = new ProceedStatus {
                    OperationStatus = OperationStatus.Error
                };
            }
            finally
            {
                _dbContext.SaveChanges();
            }
            return(response);
        }