public string BuySubscription(int accountId, string subscriptionType)
        {
            string subscriptionTypes = System.IO.File.ReadAllText("SubscriptionTypes.json");
            int    subscriptionCost;
            int    subscriptionDuration;
            string subscriptionDescription;

            using (JsonDocument doc = JsonDocument.Parse(subscriptionTypes))
            {
                JsonElement root       = doc.RootElement;
                JsonElement jsSubsType = root.GetProperty(subscriptionType);

                subscriptionCost        = jsSubsType.GetProperty("cost").GetInt32();
                subscriptionDuration    = jsSubsType.GetProperty("duration").GetInt32();
                subscriptionDescription = jsSubsType.GetProperty("description").GetString();
            }

            if (subscriptionCost == 0 || subscriptionDuration == 0)
            {
                throw new AppException("Ошибка в указании типа подписки");
            }

            // 1. Сохраняем информацию о покупке в БД и формируем ссылку для оплаты

            Subscription newSubscription = new Subscription
            {
                UserId    = accountId,
                Type      = subscriptionType,
                Duration  = subscriptionDuration,
                Cost      = subscriptionCost,
                OrderDate = DateTime.Now
            };

            _context.Subscriptions.Add(newSubscription);
            _context.SaveChanges();

            int invoiceId = _context.Subscriptions.SingleOrDefault(x =>
                                                                   x.UserId == newSubscription.UserId &&
                                                                   x.OrderDate == newSubscription.OrderDate)
                            .Id;

            RobokassaItemModel[] robokassaItems = new RobokassaItemModel[] {
                new RobokassaItemModel {
                    name     = subscriptionDescription,
                    quantity = 1,
                    sum      = subscriptionCost,
                    tax      = "none"
                }
            };

            RobokassaReceiptModel robokassaReceipt = new RobokassaReceiptModel {
                items = robokassaItems
            };

            var robokassaInfo = GenerateRobokassaLink(subscriptionCost, subscriptionDescription, invoiceId, robokassaReceipt);

            newSubscription.OrderId = robokassaInfo.signatureValue;
            _context.Subscriptions.Update(newSubscription);
            _context.SaveChanges();

            // 2. Перенаправляем пользователя на страницу оплаты
            string url = robokassaInfo.link;

            return(url);
        }
        private (string link, string signatureValue) GenerateRobokassaLink(decimal amount, string description, int invoiceId, RobokassaReceiptModel receipt)
        {
            bool isTest = true;

            string roboShopName = _appSettings.RobokassaShopName;

            string roboFirstPassw = _appSettings.RobokassaFirstPassw;

            JsonSerializerOptions jsonOptions = new JsonSerializerOptions
            {
                Encoder          = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
                IgnoreNullValues = true
            };

            string jsStringReceipt = JsonSerializer.Serialize <RobokassaReceiptModel>(receipt, jsonOptions);

            // кодировать Receipt нужно 1 раз для расчета сигнатуры и 2 раза для добавления в ссылку,
            // т.к. браузер автоматически декодирует его (так сказали в техподдержке робокассы)
            string signatureReceipt = WebUtility.UrlEncode(jsStringReceipt);
            string urlReceipt       = WebUtility.UrlEncode(signatureReceipt);

            string
                amountStr    = amount.ToString("0.00", System.Globalization.CultureInfo.InvariantCulture),
                invoiceIdStr = invoiceId.ToString(),
                srcBase      = $"{roboShopName}:{amountStr}:{invoiceIdStr}:{signatureReceipt}:{roboFirstPassw}";
            //srcBase = $"{roboShopName}:{amountStr}:{invoiceIdStr}:{roboFirstPassw}";

            string signatureValue = generateSHA256Hash(srcBase);
            string authPaymentString;

            if (isTest)
            {
                authPaymentString = "https://auth.robokassa.ru/Merchant/Index.aspx" + "?isTest=1" +
                                    "&MrchLogin="******"&OutSum=" + amountStr +
                                    "&InvId=" + invoiceIdStr +
                                    "&Receipt=" + urlReceipt +
                                    "&Description=" + description +
                                    "&SignatureValue=" + signatureValue +
                                    "&Culture=ru";
            }
            else
            {
                authPaymentString = "https://auth.robokassa.ru/Merchant/Index.aspx" +
                                    "?MrchLogin="******"&OutSum=" + amountStr +
                                    "&InvId=" + invoiceIdStr +
                                    "&Receipt=" + urlReceipt +
                                    "&Description=" + description +
                                    "&SignatureValue=" + signatureValue +
                                    "&Culture=ru";
            }
            return(authPaymentString, signatureValue);
        }