Отвечай на вопросы, используя следующий контекст:
/// <summary>
    /// Тест-драйв
    /// </summary>
    public const string Testdrive = "TESTDRIVE";

    /// <summary>
    /// Коммерческая
    /// </summary>
    public const string Commerce = "COMMERCE";

    /// <summary>
    /// Доставка.
    /// </summary>
    public const string Delivery = "DELIVERY";

    /// <summary>
    /// Такси.
    /// </summary>
    public const string Taxi = PurposeOfUsingCodes.Taxi;

    /// <summary>
    /// Дорожные и специальные ТС.
    /// </summary>
    public const string Special = PurposeOfUsingCodes.Special;

    /// <summary>
    /// Аренда/прокат.
    /// </summary>
    public const string Rental = PurposeOfUsingCodes.Rental;

    /// <summary>
    /// Прочее.
    /// </summary>
    public const string Other = PurposeOfUsingCodes.Other;

    /// <summary>
    /// Перевозки опасных и легковоспламеняющихся грузов.
    /// </summary>
    public const string Danger = PurposeOfUsingCodes.Danger;

    /// <summary>
    /// Работы экстренных и коммунальных служб.
    /// </summary>
    public const string Municipal = PurposeOfUsingCodes.Municipal;

    /// <summary>
    /// Регулярных пассажирских перевозок или перевозок пассажиров по заказам.
    /// </summary>
    public const string Passenger = PurposeOfUsingCodes.Passenger;

    /// <summary>
    /// Учебной езды.
    /// </summary>
    public const string Learn = PurposeOfUsingCodes.Learn;

    /// <summary>
    /// Проверить валидность цели перевозки для юр.лиц.
    /// </summary>
    /// <param name="purposeOfUsing">Код цели перевозки.</param>
    /// <returns>Флаг валидности цели.</returns>
    public static bool Contains(string purposeOfUsing)
        => LegalPurposes.Any(x => x.Equals(purposeOfUsing, StringComparison.OrdinalIgnoreCase));

    private static readonly string[] LegalPurposes =
    [
        Encashment, 
        Ambulance, 
        Carsharing, 
        Testdrive, 
        Commerce, 
        Delivery,
        Rental,
        Special,
        Taxi,
        Danger,
        Municipal,
        Passenger,
        Learn,
        Other
    ];
}


# Code\Constants\RegistrationRegions.cs
﻿namespace iRIS.KaskoLink2.Code.Constants
{
    public class RegistrationRegions
    {
        public const string Moskva = "Moskva";
        public const string SanktPeterburg = "SanktPeterburg";
        public const string Kazan = "Kazan";
        public const string NizhniNovgo = "NizhniNovgo";
        public const string CHelyabinsk = "CHelyabinsk";
        public const string Novosibirsk = "Novosibirsk";
        public const string Ekaterinburg = "Ekaterinburg";
        public const string RespuTatar = "RespuTatar";
        public const string Nizhegoblas = "Nizhegoblas";
        public const string CHelyaboblas = "CHelyaboblas";
        public const string Novosoblas = "Novosoblas";
        public const string Sverdoblas = "Sverdoblas";
    }
}


# Code\Constants\SalesChainNumbers.cs
﻿namespace iRIS.KaskoLink2.Code.Constants
{
    internal static class SalesChainNumbers
    {
        /// <summary>
        /// Цепочка продаж для Страховая касса.
        /// </summary>
        public const string StrahKassaSalesChainNumber = "39435";

        /// <summary>
        /// Цепочка продаж для МИКСТЕЛЛ.
        /// </summary>
        public const string MikstellSalesChainNumber = "36820";
    }
}


# Code\Constants\SasApprovalStatusCodes.cs
﻿namespace iRIS.KaskoLink2.Code.Constants
{
    public static class SasApprovalStatusCodes
    {
        public const string Accepted = "accepted";
        public const string Rejected = "rejected";
        public const string Urm = "urm";
        public const string NoDecision = "noDecision";
    }
}

# Code\Constants\SasRequestSource.cs
﻿namespace iRIS.KaskoLink2.Code.Constants
{
    public static class SasRequestSource
    {
        public const string Constructor = "Constructor";
        public const string Questionnaire = "Questionnaire";
    }
}


# Code\Constants\SexCodes.cs
﻿namespace iRIS.KaskoLink2.Code.Constants;

public class SexCodes
{
    /// <summary>
    /// Мужской.
    /// </summary>
    public const string M = "M";

    /// <summary>
    /// Женский.
    /// </summary>
    public const string F = "F";

    /// <summary>
    /// Трансгендер.
    /// </summary>
    public const string TG = "TG";

    public static readonly string[] AvailableSexCodes = { M, F };
}


# Code\Constants\SexNames.cs
﻿namespace iRIS.KaskoLink2.Code.Constants;

public class SexNames
{
    public const string M = "Мужской";
    public const string F = "Женский";
    public const string TG = "Трансгендер";
}


# Code\Constants\StructIdsCodes.cs
﻿namespace iRIS.KaskoLink2.Code.Constants
{
    public static class StructIdsCodes
    {
        public const int AddEquipment = 5034;

        /// <summary>
        /// Аварийный комиссар: выезд на любое ДТП.
        /// </summary>
        public const int AvarcomAccident = 5013;

        /// <summary>
        /// Аварийный комиссар: выезд на любое страховое событие.
        /// </summary>
        public const int AvarcomAny = 5551;

        /// <summary>
        /// Аварийный комиссар: сбор справок.
        /// </summary>
        public const int AvarcomNote = 5014;

        /// <summary>
        /// Аварийный комиссар: выезд на ДТП с двумя и более участниками или пострадавшими по жизни и здоровью.
        /// </summary>
        public const int Avarcom2Par = 5012;

        /// <summary>
        /// Угон/хищение.
        /// </summary>
        public const int CarjackingCode = 5031;

        /// <summary>
        /// Ущерб.
        /// </summary>
        public const int Damage = 5016;

        /// <summary>
        /// Ремонт на СТОА дилера по направлению Страховщика.
        /// </summary>
        public const int DealerTechcenter = 5485;

        /// <summary>
        /// Эвакуация.
        /// </summary>
        public const int Evacuation = 5004;

        public const int FranchiseCauser = 5027;

        public const int FranchiseSecondIncEvent = 5028;

        /// <summary>
        /// GAP (страхование на полную стоимость).
        /// </summary>
        public const int Gap = 5036;

        /// <summary>
        /// Стекла без справок 1 раз в год.
        /// </summary>
        public const int Glass1T = 5018;

        /// <summary>
        /// Стекла без справок без ограничений.
        /// </summary>
        public const int GlassMany = 5019;

        public const int InstallmentPaymentsCode = 5096;

        /// <summary>
        /// Ремонт на СТОА по выбору Страхователя.
        /// </summary>
        public const int InsurantTechcenter = 5486;

        public const int Milelimit = 5023;

        public const int OneTimePaymentCode = 5097;

        /// <summary>
        /// Выплата без справок по кузовным деталям до 3% от страховой суммы один раз в год (BODY3P1T).
        /// </summary>
        public const int Percent3 = 5020;

        /// <summary>
        /// Выплата без справок по кузовным деталям до 5% от страховой суммы два раза в год (BODY5P2T).
        /// </summary>
        public const int Percent5 = 5021;

        public const int ProductKasko = 3042;

        /// <summary>
        /// Аренда автомобиля.
        /// </summary>
        public const int Rent = 5011;

        /// <summary>
        /// Такси.
        /// </summary>
        public const int Taxi = 5005;

        /// <summary>
        /// Ремонт на СТОА (кроме дилеров) по направлению Страховщика.
        /// </summary>
        public const int Techcenter = 5484;

        /// <summary>
        /// Техпомощь.
        /// </summary>
        public const int TechHelp = 5006;

        /// <summary>
        /// Ущерб только на условиях "Полная гибель".
        /// </summary>
        public const int TotalLoss = 5029;
    }
}


# Code\Constants\UrmApprovalThemeProlongationCodes.cs
﻿namespace iRIS.KaskoLink2.Code.Constants
{
    public static class UrmApprovalThemeProlongationCodes
    {
        public const string ChangeOwner = "changeOwner";
        public const string ChangeInsurant = "changeInsurant";
        public const string Other = "other";
    }
}


# Code\Constants\UserGroupConstant.cs
﻿namespace iRIS.KaskoLink2.Code.Constants
{
    public class UserGroupConstant
    {
        public const string Nb_grs = "НБ ГРС";
        public const string Nb_intouch = "НБ Интач";
        public const string Nb_grs_supervizor = "НБ ГРС Супервайзер";
        public const string Nb_intouch_supervizor = "НБ Интач Супервайзер";
        public const string CallCenter = "CallCenter";
        public const string Delivery = "Delivery";
        public const string Clients = "Clients";
        public const string URM = "URM";
        public const string DIUnderwriter = "DIUnderwriter";
        public const string Link2Agents = "Link2Agents";
        public const string Administrators = "Administrators";
        public const string COK = "COK";
        public const string HelpDesk = "HelpDesk";
    }
}


# Code\Constants\UserModeCodes.cs
﻿namespace iRIS.KaskoLink2.Code.Constants
{
    internal class UserModeCodes
    {
        public const string CallCenter = "CallCenter";
        public const string Supervisor = "Supervisor";
    }
}


# Code\Constants\ConstantsHelpers\SASApprovalStatusCodeHelper.cs
﻿using iRIS.InsuranceCore.Entities.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace iRIS.KaskoLink2.Code.Constants.ConstantsHelpers
{
    public static class SASApprovalStatusCodeHelper
    {
        public static string GetSASStatusCode(string kaskoSasCheckProcessConstant)
        {
            switch (kaskoSasCheckProcessConstant)
            {
                case KaskoSasCheckProcessConstants.KaskoSasCheckAccept:
                    return SASApprovalStatusCodes.Accepted;
                case KaskoSasCheckProcessConstants.KaskoSasCheckUrm:
                    return SASApprovalStatusCodes.Urm;
                case KaskoSasCheckProcessConstants.KaskoSasCheckNoDecision:
                    return SASApprovalStatusCodes.NoDecision;
                case KaskoSasCheckProcessConstants.KaskoSasCheckReject:
                default:
                    return SASApprovalStatusCodes.Rejected;
            }
        }
    }
}


# Code\Constructor\ConstructorModule.cs
﻿using Autofac;
using iRIS.InsuranceCore.Code.Constructor;
using iRIS.KaskoCore.Code.Implementations;
using iRIS.KaskoCore.Code.Interfaces;
using iRIS.KaskoLink2.Code.Constructor.Implementations;
using iRIS.KaskoLink2.Code.Constructor.Implementations.CallCenterConstructor;
using iRIS.KaskoLink2.Code.Constructor.Implementations.ClientConstructor;
using iRIS.KaskoLink2.Code.Constructor.Interfaces;
using iRIS.KaskoLink2.ViewModels;

namespace iRIS.KaskoLink2.Code.Constructor
{
    public class ConstructorModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<ConstructorOfferGetter>().As<IConstructorOfferGetter>();
            builder.RegisterType<ConstructorCacheWrapper>().As<IConstructorCacheWrapper>();
            builder.RegisterType<ToggleConditionHandler>().As<IToggleConditionHandler>();
            builder.RegisterType<ConstructorSiebelWrapper>().As<IConstructorSiebelWrapper>();
            builder.RegisterType<KaskoDeltaProcessor>().As<IKaskoDeltaProcessor>();
            builder.RegisterType<CallcenterConstructorDataWrapper>().As<IConstructorDataWrapper<DiKaskoConstructorStepViewModel>>();
            builder.RegisterType<ClientConstructorDataWrapper>().As<IConstructorDataWrapper<DiKaskoClientConstructorStepViewModel>>();
            builder.RegisterType<CallcenterConstructorCalculator>().As<IConstructorCalculator<DiKaskoConstructorStepViewModel>>();
            builder.RegisterType<ClientConstructorCalculator>().As<IConstructorCalculator<DiKaskoClientConstructorStepViewModel>>();
            builder.RegisterType<ConstructorDiscountsLogic>().As<IConstructorDiscountsLogic<DiKaskoConstructorStepViewModel>>();
            builder.RegisterType<CallcenterConstructorLogic>().As<IConstructorLogic<DiKaskoConstructorStepViewModel>>();
            builder.RegisterType<ClientConstructorLogic>().As<IConstructorLogic<DiKaskoClientConstructorStepViewModel>>();
            builder.RegisterType<CallcenterConstructorModelUpdater>().As<IConstructorModelUpdater<DiKaskoConstructorStepViewModel>>();
            builder.RegisterType<ClientConstructorModelUpdater>().As<IConstructorModelUpdater<DiKaskoClientConstructorStepViewModel>>();
            builder.RegisterType<CallcenterConstructorViewModelUpdater>().As<IConstructorViewModelUpdater<DiKaskoConstructorStepViewModel>>();
            builder.RegisterType<ClientConstructorViewModelUpdater>().As<IConstructorViewModelUpdater<DiKaskoClientConstructorStepViewModel>>();
            builder.RegisterType<ConstructorDiscountModelUpdater>().As<IConstructorDiscountModelUpdater<DiKaskoConstructorStepViewModel>>();
            builder.RegisterType<KaskoDiscountApplier>().As<IDiscountApplier>().SingleInstance();
        }
    }
}


# Code\Constructor\KaskoConstructorOfferGetter.cs
﻿using iRIS.Framework.Cqrs.Interfaces;
using iRIS.Framework.Entity.Dictionary.EntitySettings;
using iRIS.InsuranceCore.Code.ExternalFunctions;
using iRIS.InsuranceCore.Code.Queries;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Entities.EntityExtensions;
using iRIS.KaskoCore.Code.Constants;
using iRIS.KaskoCore.Code.Extensions;
using iRIS.KaskoLink2.Code.Helpers;
using Serilog;
using System;

namespace iRIS.KaskoLink2.Code.Constructor
{
    public interface IKaskoConstructorOfferGetter
    {
        int GetConstructorOfferId(Basket basket, string loginName = null);
    }

    public class KaskoConstructorOfferGetter : IKaskoConstructorOfferGetter
    {
        public static int[] ConstructorOffers { get; set; } = new int[] 
        {
            DiKaskoOfferIds.Link2Constructor,
            DiKaskoOfferIds.Constructor,
            B2BKaskoOfferIds.KaskoKKP,
            B2BKaskoOfferIds.KaskoKKPProlongation
        };

        private readonly Link2FunctionsInvoker _invoker;
        private readonly ILogger _logger;
        private readonly IEntitySettingsManager _entitySettingsManager;
        private readonly ICqrsMediator _mediator;

        public KaskoConstructorOfferGetter(Link2FunctionsInvoker invoker, ILogger logger, IEntitySettingsManager entitySettingsManager, ICqrsMediator mediator)
        {
            _invoker = invoker;
            _logger = logger;
            _entitySettingsManager = entitySettingsManager;
            _mediator = mediator;
        }

        public int GetConstructorOfferId(Basket basket, string loginName = null)
        {
            int selectedConstructorOfferId;
            string intLoginName = loginName ?? GetLoginName(basket);

            try
            {
                if (_invoker.BasketCreatorIsLink2PartnerOrDiAgent(basket))
                {
                    if (CheckIsB2CPartnerHelper.CheckIsB2CPartner(_entitySettingsManager, intLoginName))
                    {
                        selectedConstructorOfferId = DiKaskoOfferIds.Link2Constructor;
                    }
                    else
                    {
                        selectedConstructorOfferId = basket.HasProlongationInBasket()
                            ? B2BKaskoOfferIds.KaskoKKPProlongation
                            : B2BKaskoOfferIds.KaskoKKP;
                    }
                }
                else
                {
                    selectedConstructorOfferId = DiKaskoOfferIds.Constructor;
                }
            }
            catch (Exception e)
            {
                _logger.Error(e, "Ошибка получения оффера для конструктора Link2");
                selectedConstructorOfferId = 0;
            }

            return selectedConstructorOfferId;
        }

        private string GetLoginName(Basket basket)
        {
            var basketCreator = _mediator.ResolveQuery<IQueryBasketCreator>().GetBasketCreatorDetailed(basket.EntityId, basket.Number, null);
            var integrationLogin = _mediator.ResolveQuery<IQueryIntegrationLogin>().GetIntegrationLoginByUserId(basketCreator.User.Id);
            
            return integrationLogin.IntegrationLoginName;
        }
    }
}
sb.Append(" являются неотъемлемой частью настоящего Полиса. Принимая настоящий Полис и оплачивая страховую премию, Страхователь подтверждает, что Правила получил, ознакомлен и согласен с их условиями, а также с условиями настоящего Полиса и его приложений в полном объеме. Дополнительно с Правилами страхования можно ознакомиться на официальном сайте Страховщика renins.ru.");
            sb.Append(Environment.NewLine);
            sb.Append("Принимая настоящий полис и оплачивая страховую премию, Страхователь подтверждает, что все сведения, указанные в настоящем Полисе и в его приложениях, являются полными и достоверными. Стороны пришли к соглашению, что настоящий Полис и любые документы в рамках настоящего Полиса могут быть подписаны Страховщиком с использованием факсимиле или электронной подписи уполномоченного представителя Страховщика. В случае разночтений между условиями настоящего Полиса и Правилами приоритет будут иметь условия настоящего Полиса.");
            sb.Append(Environment.NewLine);
            sb.Append("Принимая настоящий полис и оплачивая страховую премию, Страхователь подтверждает, что он не является иностранными публичным должностным лицом и / или его родственником, должностным лицом публичной международной организации, а также лицом, замещающим(занимающим) государственную должность РФ, должность члена Совета Директоров ЦБ РФ, должность федеральной государственной службы, назначение и освобождение от которой осуществляется Президентом РФ или Правительством РФ, должность в ЦБ РФ, государственных корпорациях и иных организациях, созданных РФ на основании федеральных законов, включенную в перечни должностей, определяемые Президентом РФ.В ином случае Страхователь обязуется предоставить документы, подтверждающие должность / наименование и адрес работодателя / степень родства / статус(супруг или супруга).Также Страхователь подтверждает, что не имеет регистрации, места жительства / нахождения, счета в банке в государстве(на территории), которое(-ая) не выполняет рекомендации ФАТФ.Страхователь подтверждает, что не ограничен в дееспособности, а также его действия по иным основаниям не контролирует иное физическое лицо(бенефициарный владелец).");
            sb.Append(Environment.NewLine);
            sb.Append("Принимая настоящий Полис и оплачивая страховую премию Страхователь выражает Страховщику согласие на обработку персональных данных физических лиц, содержащихся в настоящем Полисе и в иных документах, передаваемых Страховщику для исполнения обязательств по данному Полису, а также в целях продвижения товаров, работ, услуг на рынке путем осуществления Страховщиком прямых контактов с помощью связи.");
            sb.Append(Environment.NewLine);
            sb.Append("Принимая настоящий Полис и оплачивая страховую премию Страхователь подтверждает, что в полном объеме получил информацию, предусмотренную пунктом 2.1.2. Базового стандарта защиты прав и интересов физических и юридических лиц — получателей финансовых услуг, оказываемых членами саморегулируемых организаций, объединяющих страховые организации, утв. Решением КФН ЦБ РФ, Протокол от 09.08.18 № КФНП-24. Принимая настоящий Полис и оплачивая страховую премию Страхователь выражает согласие осуществлять взаимодействие со Страховщиком путем обращения в офисы Страховщика, посредствам почтовой и телефонной связи, а также иными способами в случаях, специально предусмотренных Правилами страхования. Принимая настоящий Полис и оплачивая страховую премию Страхователь выражает согласие получать сообщения и уведомления от Страховщика, в том числе в электронной форме, по адресам, телефонам, указанным в настоящем Полисе. Информация об адресах офисов Страховщика, в которых осуществляется прием документов при наступлении страховых случаев и иных обращений, а также о случаях и порядке приема документов в электронной форме, размещена на официальном сайте Страховщика и может быть получена при обращении по телефонам Страховщика, указанным в настоящем Полисе.");
            return sb.ToString();
        }

        public List<PsoAdditionalFieldModel> CreatePsoAdditionalFields(Basket basket)
        {
            var deal = basket.GetKaskoDeal();
            var auto = deal.GetInsObjectAuto();

            var result = new List<PsoAdditionalFieldModel>
            {
                CreatePsoAdditionalFieldValueModel("policy_number", deal.PolicyNumber),
                CreatePsoAdditionalFieldValueModel("marka_model", string.Join(", ", auto.AutoBrandName, auto.AutoModelName)),
                CreatePsoAdditionalFieldValueModel("VIN", auto.Vin),
                CreatePsoAdditionalFieldValueModel("rate_num", basket.Number),
                CreatePsoAdditionalFieldValueModel("GRZ", auto.RegistrationNumber)
            };

            return result.Where(x => x != null).ToList();
        }

        public bool ReadConfigBooleanVariable(string variableName)
        {
            var configService = ServiceProvider.GetRequiredService<IConfigurationRoot>();
            return configService.GetValue<bool>(variableName);
        }

        public string ReadConfigStringVariable(string variableName)
        {
            var configService = ServiceProvider.GetRequiredService<IConfigurationRoot>();
            return configService.GetValue<string>(variableName);
        }

        public string GetUrlResumeProcessKaskoWithToken(AuthorizationData authorizationData, Basket basket)
        {
            return GetUrlResumeProcessKaskoWithToken(authorizationData, basket, false);
        }

        public string GetUrlResumeProcessKaskoWithToken(AuthorizationData authorizationData, Basket basket, bool isReusable)
        {
            // Из фрейма на сайте интача не получается сделать редирект из процесса оплаты обратно в процесс Каско
            if (basket.IsIntouchWeb())
            {
                return null;
            }

            var resumeProcessUrlGetter = ServiceProvider.GetRequiredService<IKaskoResumeProcessUrlGetter>();

            return resumeProcessUrlGetter.GetUrlResumeProcessKaskoWithToken(authorizationData.CurrentUserId, authorizationData.BrowserSessionId, basket, isReusable);
        }

        public void SelectConstructorProposal(Basket basket)
        {
            IKaskoConstructorOfferGetter constructorOfferGetter = ServiceProvider.GetService<IKaskoConstructorOfferGetter>();

            var deal = basket.GetKaskoDeal();
            var proposal = deal.Proposals.Single(p => p.Offer_Id == constructorOfferGetter.GetConstructorOfferId(basket));

            deal.SetSelectedProposal(proposal);
        }

        /// <summary>
        /// Блок по пересчету со скидкой. Копипаста из DiKaskoConstructorExtension.
        /// </summary>
        public async Task ApplyDiscount(Basket basket)
        {
            var discountCalculationHelper = ServiceProvider.GetRequiredService<DiscountCalculationHelper>();
            var calcData = discountCalculationHelper.GetCalcData(basket);

            var discountApplier = ServiceProvider.GetRequiredService<IDiscountApplier>();
            await discountApplier.CalculteWithAppliedDiscountsConsideringCombinationStatusAsync(calcData);
        }

        public void ApplyCostCenterByPromocode(Basket basket)
        {
            if (basket.PromoCode == null)
            {
                return;
            }

            var discountApplier = ServiceProvider.GetRequiredService<IDiscountApplier>();
            var promocodeManager = ServiceProvider.GetRequiredService<IPromocodeManager>();

            if (!discountApplier.IsPromoCodeAppliedAtKaskoDeal(basket))
            {
                return;
            }

            foreach (var deal in basket.Deals)
            {
                //только сделки каско
                if (deal.Product.ProductDictCode != ProductDictCodes.Kasko)
                {
                    continue;
                }

                var promocode = promocodeManager.GetActualPromocode(basket.PromoCode.Id, deal.Product.Id);

                //промкод протух
                if (promocode == null)
                {
                    continue;
                }

                discountApplier.SetDealCostCenterCodeByPromocode(deal, promocode);
            }
        }

        public bool ApplyPromocodeToDiscounts(Basket basket, Dictionary<string, string> inputModelContext)
        {
            var promocodeValue = string.Empty;
            if (inputModelContext != null && inputModelContext.ContainsKey("promocode"))
            {
                promocodeValue = inputModelContext["promocode"];
            }

            var result = ApplyPromo(basket, promocodeValue);

            // если пользователь сбросил промокод и промокод пришёл из url, то очищаем значение, принятое из url
            if (string.IsNullOrEmpty(promocodeValue) && !string.IsNullOrEmpty(basket.ExternalTagList?.PromoCode))
            {
                basket.ExternalTagList.PromoCode = string.Empty;
            }

            return result;
        }

        public bool ApplyPromocodeForLink2(Basket basket)
        {
            var kaskoDeal = basket.GetKaskoDeal();
            var promocode = kaskoDeal?.PromoCode;
            var promocodeValue = promocode?.Code;
            if (string.IsNullOrEmpty(promocodeValue))
            {
                return false;
            }

            var result = ApplyPromo(basket, promocodeValue);

            return result;
        }

        public void CreateEmptyCourierDealIntermediary(Basket basket)
        {
            var dealsWithCourierDelivery = basket.Deals.Where(x =>
                x.IsInBasket == true
                && x.IsExternal != true
                && x.Deliveries.Any(del => del.DeliveryWayCode == DeliveryWayCodes.ByCourier));

            foreach (var deal in dealsWithCourierDelivery)
            {
                var courierDealIntermediary = deal.DealIntermediaries
                    .Where(x => x.InteractionTypeCode == InteractionTypeEnum.Courier.ToString()
                                || x.Intermediary?.InteractionTypeCode == InteractionTypeEnum.Courier.ToString())
                    .FirstOrDefault();

                if (courierDealIntermediary == null)
                {
                    var courierIntermediary = new Intermediary
                    {
                        InteractionTypeCode = InteractionTypeEnum.Courier.ToString(),
                        IntermediaryStatusCode = "IntActive",
                    };
                    courierIntermediary.EntityContext[KaskoCore.Siebel.Code.Constants.EntityContextKeys.PositionTypeKey] = KaskoCore.Siebel.Code.Constants.SiebelPositionTypeNames.DeliveryDepartment;
                    deal.DealIntermediaries.Add(new DealIntermediary
                    {
                        InteractionTypeCode = InteractionTypeEnum.Courier.ToString(),
                        Intermediary = courierIntermediary
                    });
                }
            }
        }

        private bool ApplyPromo(Basket basket, string promo)
        {
            var kaskoDeal = basket.GetKaskoDeal();
            if (kaskoDeal == null)
            {
                return false;
            }

            if (string.IsNullOrWhiteSpace(promo))
            {
                ResetPromocode(basket);
                return true;
            }

            var promoCode = GetBestAvailablePromocode(promo, kaskoDeal);

            if (promoCode == null || !string.IsNullOrEmpty(promoCode.CallCenterName))
            {
                ResetPromocode(basket);

                return false;
            }

            basket.PromoCode = promoCode;

            var discountApplier = ServiceProvider.GetRequiredService<IDiscountApplier>();

            discountApplier.ApplyPromocode(kaskoDeal, promoCode, basket.ExternalTagList.UseDrafts);

            if (discountApplier.IsPromoCodeAppliedAtKaskoDeal(basket))
            {
                discountApplier.SetDealCostCenterCodeByPromocode(kaskoDeal, promoCode);
                var osagodeal = basket.GetOsagoDealInBasket();
                if (osagodeal != null)
                {
                    discountApplier.SetDealCostCenterCodeByPromocode(osagodeal, promoCode);
                }
            }

            return true;
        }

        public async Task CalculateProposals(Basket basket)
        {
            await CalculateProposalsInternalAsync(basket, DiscountCalculationStrategy.CalculateForAgreedOrApproveNotRequiredDiscounts);
        }

        private async Task CalculateProposalsInternalAsync(Basket basket, DiscountCalculationStrategy? discountCalculationStrategy = null)
        {
            var kaskoCalculationWrapper = ServiceProvider.GetRequiredService<IKaskoCalculationWrapper>();
            await kaskoCalculationWrapper.CalculateAndApplyProposalsAsync(basket, discountCalculationStrategy, true);
        }

        public async Task CalculateProposalsForLink2WithPromocode(Basket basket)
        {
            var kaskoRater = ServiceProvider.GetRequiredService<IKaskoRater>();
            await kaskoRater.CalculateDealAsync(basket, basket.GetKaskoDeal());

            basket.UpdatePrice();
        }

        public void ActivatePromocode(Basket basket)
        {
            var kaskoDeal = basket.GetKaskoDeal();
            if (kaskoDeal != null &&
                basket.PromoCode != null &&
                basket.PromoCode.Code.Contains(ReninsPlusConstants.ReninsPlusPromocodePrefix))
            {
                var code = basket.PromoCode.Code.Replace(ReninsPlusConstants.ReninsPlusPromocodePrefix, string.Empty);
                var reninsPlusPromocodeService = ServiceProvider.GetRequiredService<IReninsPlusPromocodeService>();
                reninsPlusPromocodeService.ActivatePromocode(
                    code, kaskoDeal.PolicyNumber, PolicyType.Kasko);
            }
        }

        public void CorrectDeliveryDate(Basket basket, bool isProcessApiRequest)
        {
            if (isProcessApiRequest && basket.BasketStatusCode == "Registration")
            {
                var kaskoDeal = basket.GetKaskoDeal();

                var delivery = kaskoDeal?.GetLastDelivery();

                if (delivery?.Date?.Date <= DT.Now.Date && delivery?.DeliveryWayCode == DeliveryWayCodes.Email)
                {
                    delivery.Date = DT.Now.AddDays(1);
                }
            }
        }

        public void ApplyDealsConditions(List<Deal> deals, List<DealConditions> dealsConditions)
        {
            var kaskoDealManager = ServiceProvider.GetRequiredService<IDiKaskoDealManager>();
            kaskoDealManager.ApplyDealsCondition(deals, dealsConditions.Convert());
        }

        private void ResetPromocode(Basket basket)
        {
            var kaskoDeal = basket.Deals.SingleOrDefault(d => d.Product.ProductDictCode == ProductDictCodes.Kasko);
            if (kaskoDeal == null)
            {
                return;
            }

            //clear from discount
            var discountApplier = ServiceProvider.GetRequiredService<IDiscountApplier>();
            discountApplier.ClearPromocode(kaskoDeal, basket.ExternalTagList.UseDrafts);
            var constructorCacheWrapper = ServiceProvider.GetRequiredService<IConstructorCacheWrapper>();
            var constructorDeal = constructorCacheWrapper.GetDealFromCache(kaskoDeal.Id);
            if (constructorDeal != null)
            {
                discountApplier.ClearPromocode(constructorDeal, basket.ExternalTagList.UseDrafts);
                constructorCacheWrapper.SaveDealInCache(constructorDeal);
            }

            if (basket.PromoCode?.Code != null
                && basket.PromoCode.Code.Contains(ReninsPlusConstants.ReninsPlusPromocodePrefix))
            {
                var reninsPlusService =
                    ServiceProvider.GetRequiredService<IReninsPlusPromocodeService>();
                var promoCode = basket.PromoCode.Code.Replace(
                    ReninsPlusConstants.ReninsPlusPromocodePrefix,
                    string.Empty);
                reninsPlusService.UnholdPromocode(promoCode, PolicyType.Kasko);
            }

            basket.PromoCode = null;
/// <summary>
        /// Проверка, что есть необходимость отправки в Siebel.
        /// </summary>
        /// <param name="authData">Авторизационная дата.</param>
        /// <param name="saveDraft"></param>
        /// <param name="isLead"></param>
        /// <param name="isProlongation"></param>
        /// <param name="getKaskoProlongationSendToSiebel"></param>
        /// <returns>True если есть необходимость отправки в Siebel.</returns>
        public bool CheckNeedSendSiebel(AuthorizationData authData, string saveDraft, bool isLead, bool isProlongation, bool getKaskoProlongationSendToSiebel)
        {
            var isLink2DiAgents = CurrentUserIsLink2DiAgents(authData);
            return (isLink2DiAgents && saveDraft == "True")
                         || (!isLink2DiAgents && isLead)
                         || (!isLink2DiAgents && isProlongation && getKaskoProlongationSendToSiebel);
        }

        /// <summary>
        /// Проверка, что пользователь является Link2DiAgent.
        /// </summary>
        /// <param name="authData">Авторизационная дата.</param>
        /// <returns>True если партнер Link2DiAgent.</returns>
        private bool CurrentUserIsLink2DiAgents(AuthorizationData authData)
        {
            var groupNames = GetUserGroups(authData);

            return groupNames.Contains(UserGroups.Link2DiAgents);
        }

        private IEnumerable<string> GetUserGroups(AuthorizationData authorizationData)
        {
            if (authorizationData.IsAnonymous)
            {
                return new[] { UserGroups.Anonymous };
            }

            if (authorizationData.IsRegistered)
            {
                return new[] { UserGroups.Registered };
            }

            if (authorizationData.IsAuthenticated)
            {
                var user = GetUser(authorizationData.CurrentUserId);
                if (user?.Groups != null)
                {
                    return user.Groups.Select(g => g.Name).ToArray();
                }
            }

            return Array.Empty<string>();
        }

        private bool DriversIsFilled(Deal deal)
        {
            if (deal == null || deal.AutoDeal == null)
            {
                return false;
            }

            var multidrive = deal.AutoDeal.IsMultidrive == true;

            if (multidrive)
            {
                return multidrive;
            }

            if (deal.AutoDeal.Drivers == null)
            {
                return false;
            }

            bool driversIsFilled = true;

            //Driver.Subject.IndividualEntity.Person.Age
            //Driver.DrivingExperiences[0].FullDrivingExperience
            foreach (var driver in deal.AutoDeal.Drivers)
            {
                driversIsFilled &= driver?.Subject?.IndividualEntity?.Person?.Age.HasValue == true;
                driversIsFilled &= driver?.DrivingExperiences?.FirstOrDefault()?.FullDrivingExperience.HasValue == true;
            }

            return driversIsFilled;
        }

        private bool AutoIsFilled(Deal deal)
        {
            var auto = deal.GetAuto();
            return
                !string.IsNullOrEmpty(auto.AutoBrandCode)
                && !string.IsNullOrEmpty(auto.AutoModelCode)
                && !string.IsNullOrEmpty(auto.AutoYearOfIssueCode)
                && !string.IsNullOrEmpty(auto.AutoEnginePowerCode);
        }

        public bool CheckDealWithoutInspection(Basket basket)
        {
            var isWithoutInspection = _checkManager.DealWithoutInspection(basket);
            return isWithoutInspection;
        }

        // https://jira.renins.com/browse/IRIS-159103
        public string GetUpsalesInfo(Basket basket)
        {
            return string.Empty;
        }

        public bool CheckIsAllowedToUseBSIForLink2(Basket basket)
        {
            var isCheckHistoryInBsi = basket.GetKaskoDeal()?.AutoDeal.IsCheckHistoryInBsi ?? false;

            return CheckIsAllowedToUseBsi(basket) && isCheckHistoryInBsi;
        }

        public bool CheckIsAllowedToUseBSIForCallCenter(Basket basket)
        {
            return CheckIsAllowedToUseBsi(basket);
        }

        private bool CheckIsAllowedToUseBsi(Basket basket)
        {
            return _bsiRequestAllowanceChecker.CheckIsAllowedToUseBsi(basket);
        }

        public decimal GetSellerCoefficientMin(Basket basket)
        {
            var osagoDeal = basket.GetOsagoDeal();
            var sellerCoefMin = _sellerCoefficientManager.GetSellerCoefMin(osagoDeal);

            return sellerCoefMin;
        }

        /// <summary>
        /// AB-Test переход на конструктор клиента.
        /// </summary>
        /// <returns><see href="true"/> - переход на конструктор клиента.</returns>
        public bool IsShowClientConstructor() => _abTestHelper.IsShowClientConstructor();

        /// <summary>
        /// Проверяет что все сделки в корзине пролонгационные, или нет.
        /// </summary>
        /// <param name="basket">Корзина.</param>
        /// <param name="examineProlongationValue">Значение признака пролонгации сделки, да или нет.</param>
        /// <returns>Да или нет.</returns>
        public bool CheckForProlongation(Basket basket, bool examineProlongationValue)
        {
            return basket.Deals
                .Where(x => x.IsInBasket == true)
                .All(x => x.IsProlongation == examineProlongationValue);
        }

        /// <summary>
        /// Доступность пролонгации.
        /// </summary>
        /// <param name="authorizationData"></param>
        /// <param name="basket">Корзина.</param>
        /// <returns> Значение настройки KaskoProlongationSendToSiebel</returns>
        public bool GetAvailableProlongation(AuthorizationData authorizationData, Basket basket)
        {
            var loginName = GetIntegrationLoginName(authorizationData, basket);
            var intermediary = GetKaskoIntermediary(basket);
            var deal = basket.GetKaskoDeal();

            if (deal.IsProlongation == true && !IsAllowUpdateCostCenterForProlongation(intermediary))
            {
                var parentDealCostCenterNameFromOss = deal.ParentDeal.CostcenterNameFromOss;
                var channels = _entitySettingsManager.GetSettingForDefaultOrPartnerConfiguration<List<string>>(
                    EntitySettingCodes.AvailableProlongationSalesChannel,
                    EntitySettingCodes.AvailableProlongationSalesChannelDefault,
                    EntitySettingCodes.AvailableProlongationSalesChannelPartner,
                    new IntegrationLogin()
                    {
                        IntegrationLoginName = loginName
                    },
                    new List<string>(),
                    _logger);

                if (channels.Contains(FullAvailableSalesChannel) ||
                    (channels.Any(c => parentDealCostCenterNameFromOss.Contains(c))
                    && channels.Contains(deal.CostcenterCode)))
                {
                    return true;
                }

                _validationResultsAggregator.AppendValidationErrors(new ValidationError()
                {
                    ErrorMessage = "Код: 300027.Расчет пролонгации недоступен для данного КП",
                    CriticalLevel = ValidationCriticalLevel.CantContProc
                });

                return false;
            }

            return true;
        }

        /// <summary>
        /// Получение персоны в зависимости от ответственного за ПСО.
        /// </summary>
        public Person GetInspectionPerson(Basket basket, string psoResponsibleCode)
        {
            if (psoResponsibleCode == InspectionResponsibleCodes.CurrentUser)
            {
                var intermediary = basket
                    .GetKaskoDeal()
                    .GetIntermediary();

                if (intermediary == null)
                {
                    throw new ArgumentNullException("Не указан посредник с ролью Агент или Продавец");
                }

                return intermediary.Subject
                    .IndividualEntity
                    .Person;
            }

            return basket.GetKaskoDeal().Insurant.Subject.IndividualEntity.Person;
        }

        #region Obsolete функции для поддержки старых версий процессов
        [Obsolete("Удалить после апреля 2024го года")]
        public bool IsPromoCodeApplied(Basket basket)
        {
            return _discountApplier.IsPromoCodeAppliedAtKaskoDeal(basket);
        }

        [Obsolete("Удалить после апреля 2024го года")]
        public bool CheckIsRusfinancebank(Basket basket)
        {
            return basket.HasIntermediary(IntermediaryCodes.Rusfinancebank);
        }

        /// <summary>
        /// Получить UserId страхователя.
        /// </summary>
        [Obsolete("Удалить после апреля 2024го года")]
        public int GetInsurantUserId(Basket basket)
        {
            var person = basket.GetKaskoDeal().GetInsurantPerson();

            var user = _queryUser.GetUserByEmail(person.Email1);

            return user.Id;
        }

        /// <summary>
        /// Оплата просрочена.
        /// </summary>
        /// <param name="basket">корзина.</param>
        /// <returns> Если оплата просрочена - true.</returns>
        [Obsolete("Удалить после апреля 2024го года")]
        public bool IsOverduePayment(Basket basket)
        {
            var deals = basket
              .Deals
              .Where(d => d.IsInBasket == true && !d.DealStatusCode.InEnum(EntityStatusType.Signed, EntityStatusType.PolicyIssued));

            var dateRepayment = deals
            .Select(d =>
            {
                _paymentInvoiceInitializer.InitializeInvoiceByDeal(d, out var dateRepay);
                return dateRepay;
            })
            .Min();

            return dateRepayment != null && dateRepayment < DT.Now;
        }
        #endregion

        // Логика LKA-151
        private bool IsAllowUpdateCostCenterForProlongation(Intermediary intermediary)
        {
            var settingValue = _entitySettingsManager.GetSettingForDefaultOrPartnerConfiguration(
                EntitySettingCodes.AllowUpdateCostCenterForProlongation,
                EntitySettingCodes.AllowUpdateCostCenterForProlongationDefault,
                EntitySettingCodes.AllowUpdateCostCenterForProlongationPartner,
                intermediary,
                false,
                _logger);
            return settingValue;
        }

        public Intermediary GetIsMainIntermediary(Basket basket)
        {
            return basket.GetKaskoDeal().DealIntermediaries.Single(di => di.IsMain == true).Intermediary;
        }

        public string GetSas(Basket basket)
        {
            return basket.GetKaskoDeal().AutoDeal.AutoCheckResults.Any(acr => acr.Name == "SasDataKaskoCheck")
                ? "[SAS]"
                : string.Empty;
        }

        public string GetOtaIsRepeated(Basket basket)
        {
            if (basket.GetKaskoDeal().AutoDeal.TryGetLastOtaApproval(out var approval) && approval.IsRepeated == true)
            {
                return "Повторно. ";
            }
            else
            {
                return string.Empty;
            }
        }

        public string GetUrmApprovalInfoMarkup(Basket basket)
        {
            var urmApproval = basket.GetKaskoDeal().AutoDeal.GetLastUrmApproval();
            var discount = GetUrmDiscount(basket);
            var markup = new StringBuilder("Добрый день!<br/>");
            markup.Append($"<br/>Статус согласования: {urmApproval.URMApprovalStatus.Name}<br/>");
            if (discount != null && discount.DiscountValue.HasValue && discount.DiscountValue.Value != 1m)
            {
                markup.Append($"<br/>Коэффициент УРМ: {discount.DiscountValue.Value.ToString(CultureInfo.InvariantCulture)}<br/>");
            }

            markup.Append($"<br/>Комментарий: {urmApproval.URMApprovalComment}<br/>");

            return markup.ToString();
        }

        public string GetOtaApprovalInfoMarkup(Basket basket)
        {
            var markup = new StringBuilder();
            if (basket.GetKaskoDeal().AutoDeal.TryGetLastOtaApproval(out var approval))
            {
                markup.Append($"Статус проверки: {approval.OtaApprovalStatus.Name}");
                foreach (var checkError in approval.OtaApprovalCheckErrors)
                {
                    markup.Append($"<br/>Наименование ошибки: {checkError.OtaApprovalMistake.Name}");
                    if (!string.IsNullOrEmpty(checkError.ErrorComment))
                    {
                        markup.Append($"<br/>Комментарий к ошибке: {checkError.ErrorComment}");
                    }
                }

                if (approval.OtaApprovalStatusCode == OtaApprovalStatusCodes.NonCriticalMistakes)
                {
                    markup.Append($"<br/>Возможно дальнейшее оформление полиса");
                }
            }

            return markup.ToString();
        }

        public bool IsNecessaryToRecalculateDueToUrmCoefficient(Basket basket)
        {
            var discount = GetUrmDiscount(basket);

            return discount != null && discount.DiscountSwitchOnOff == true && discount.DiscountValue != 1m;
        }

        /// <summary>
        /// Проверка необходимости захода в подпроцесс УРМ (подпроцесс возобновления).
        /// </summary>
        /// <param name="basket"></param>
        /// <returns>true, если УРМ в статусе, доступном для редактирования, либо завершена и нет проверок ОТА/ПСО (для корректной работы основного процесса).</returns>
        public bool IsUrmStepAccessible(Basket basket)
        {
            var deal = basket.GetKaskoDeal();
            if (deal.DealStatusCode != EntityStatusType.InWork.ToString())
            {
                return false;
            }

            if (!basket.GetKaskoDeal().AutoDeal.TryGetLastUrmApproval(out var approval))
            {
                return false;
            }

            // Для случая, когда назначена только проверка УРМ после выставления финального статуса
            // необходимо еще раз зайти в подпроцесс и пройти по нему до смены статусов корзины и сделок.
            if (UrmStatusHelper.UrmCompletedStatuses.Contains(approval.URMApprovalStatusCode) && !IsOtaStepAdded(basket))
            {
                var inspection = _mediator.ResolveQuery<IQueryKaskoInspection>().GetInspectionByDealEntityId(deal.EntityId);

                return inspection == null;
            }

            return UrmStatusHelper.UrmAddedStatuses.Contains(approval.URMApprovalStatusCode);
        }

        public bool IsUrmStatusInWork(Basket basket)
        {
            if (basket.GetKaskoDeal().AutoDeal.TryGetLastUrmApproval(out var approval))
            {
                return approval.URMApprovalStatusCode.Equals(UrmApprovalStatusCodes.InWork, StringComparison.OrdinalIgnoreCase);
            }

            return false;
        }

        public bool CheckUrmApprovalStatusEqualsTo(Basket basket, string status)
        {
            if (basket.GetKaskoDeal().AutoDeal.TryGetLastUrmApproval(out var approval))
            {
                return approval.URMApprovalStatusCode == status;
            }

            return false;
        }

        public bool CheckOtaApprovalStatusEqualsTo(Basket basket, string status)
        {
            if (basket.GetKaskoDeal().AutoDeal.TryGetLastOtaApproval(out var approval))
            {
                return approval.OtaApprovalStatusCode == status;
            }

            return false;
        }

        /// <summary>
        /// Проверка необходимости прохождения подпроцесса ОТА/ПСО (подпроцесс ОТА/ПСО).
        /// </summary>
        /// <param name="basket"></param>
        /// <returns></returns>
        public bool IsOtaPsoStepNecessary(Basket basket)
        {
            var deal = basket.GetKaskoDeal();

            var inspection = _mediator.ResolveQuery<IQueryKaskoInspection>().GetInspectionByDealEntityId(deal.EntityId);
# Code\Constructor\CalculationPartner\CalculationPartnerRequest\ICalculationPartnerRequestClient.cs
﻿namespace iRIS.KaskoLink2.Code.Constructor.CalculationPartner.CalculationPartnerRequest
{
    internal interface ICalculationPartnerRequestClient
    {
        /// <summary>
        /// Запросить токен авторизации
        /// </summary>
        /// <returns>Токен авторизации (живет около 3 минут)</returns>
        string GetAuthToken();

        /// <summary>
        /// Запрос партнеру для получения Id расчета других СК.
        /// </summary>
        /// <param name="queryString">GET параметры для расчета</param>
        /// <returns>Id запроса</returns>
        string GetRequestId(string queryString);

        /// <summary>
        /// Запрос партнеру для получения расчетов других СК.
        /// </summary>
        /// <param name="queryString">GET параметры для расчета</param>
        void GetKaskoCalc(string queryString);
    }
}

# Code\Constructor\CalculationPartner\CalculationPartnerRequest\QueryStringBuilder.cs
﻿using System.Collections.Generic;
using System.Linq;
using Castle.Core.Internal;
using iRIS.Framework.Common;
using iRIS.InsuranceCore.Code.Extensions.Helpers;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Entities.EntityExtensions;

namespace iRIS.KaskoLink2.Code.Constructor.CalculationPartner.CalculationPartnerRequest
{
    internal class QueryStringBuilder
    {
        private readonly CalculationMapHelper _calculationMapHelper;
        
        public QueryStringBuilder(CalculationMapHelper calculationMapHelper)
        {
            _calculationMapHelper = calculationMapHelper;
        }

        public void AppendToken(ref string queryString, string token)
        {
            queryString = $"token={token}&{queryString}";
        }

        public void AppendRequestId(ref string queryString, string requestId)
        {
            queryString = $"requestid={requestId}&{queryString}";
        }

        public string ToQueryString(Deal deal)
        {
            var queryParams = new Dictionary<string, string>();
            var auto = deal.GetAuto();

            AddAutoParams(auto, queryParams);
            AddConstructorParams(deal, queryParams);
            AddStaticParams(queryParams);
            AddDriversParam(deal.AutoDeal, queryParams);
            AddRegionParam(deal, queryParams);

            if (auto.IsCreditAuto == true)
            {
                queryParams.Add("bik", deal.SuggestedBanks.Last().BIK);
            }

            if (auto.HasAntiTheftSystem == true)
            {
                var antiTheftSystem = auto.AntiTheftSystems.First();
                queryParams.Add("antiTheftSystemBrandCode", antiTheftSystem.AntiTheftSystemBrandCode);
                queryParams.Add("antiTheftName", antiTheftSystem.AntiTheftSystemModel.Name.Replace(" + ", "%2b"));
            }
            else
            {
                queryParams.Add("ops", "нет");
            }

            return string.Join("&", queryParams.Select(param => $"{param.Key}={param.Value}"));
        }

        private void AddDriversParam(AutoDeal autoDeal, Dictionary<string, string> queryParams)
        {
            if (autoDeal.IsMultidrive != true)
            {
                for (var index = 0; index < autoDeal.Drivers.Count; index++)
                {
                    var driver = autoDeal.Drivers[index];

                    queryParams.Add($"drivers[{index}][sex]", "M");
                    queryParams.Add($"drivers[{index}][age]", $"{driver.Subject.IndividualEntity.Person.Age}");
                    queryParams.Add($"drivers[{index}][exp]", $"{driver.DrivingExperiences.First().FullDrivingExperience}");
                    queryParams.Add($"drivers[{index}][childs]", "0");
                    if (driver.Subject.IndividualEntity.Person.IsMaried == true)
                    {
                        queryParams.Add($"drivers[{index}][married]", "Да");
                    }
                }
            }
            else
            {
                queryParams.Add("accepted_drivers", "Неограниченное количество");
                queryParams.Add("min_age", "18");
                queryParams.Add("min_exp", "0");
            }
        }

        private void AddConstructorParams(Deal deal, Dictionary<string, string> queryParams)
        {
            var dealHelper = new DealHelper(deal);
            var compensation = _calculationMapHelper.Compensation(dealHelper);
            if (!compensation.IsNullOrEmpty())
            {
                queryParams.Add("compensation", compensation);
            }

            var franchise = _calculationMapHelper.Franchise(dealHelper);
            if (franchise != null)
            {
                queryParams.Add("fransh", $"{DecimalToString(franchise)}");
            }
        }

        private void AddAutoParams(Auto auto, Dictionary<string, string> queryParams)
        {
            queryParams.Add("begindate", $"01.01.{auto.AutoYearOfIssueCode}");
            queryParams.Add("creationyear", $"{auto.AutoYearOfIssueCode}");
            queryParams.Add("power", $"{DecimalToString(auto.AutoEnginePowerValue)}");
            queryParams.Add("carprice", $"{DecimalToString(auto.AutoCost)}");
            queryParams.Add("mark", $"{auto.AutoBrandName}");
            queryParams.Add("model", $"{auto.AutoModelName}");
            queryParams.Add("transmission", $"{auto.AutoTransmissionTypeCode}");
            queryParams.Add("fuel", $"{auto.AutoEngineTypeCode}");
            queryParams.Add("carbody", $"{auto.AutoBodyTypeCode}");

            if (!string.IsNullOrEmpty(auto.AutoModification?.AutoEngineValueCode))
            {
                queryParams.Add("engine_capacity", $"{auto.AutoModification.AutoEngineValueCode}");
            }

            if (auto.HasMileage == true)
            {
                queryParams.Add("miliage", auto.Mileage.HasValue ? auto.Mileage.ToString() : "0");
            }
            else
            {
                queryParams.Add("new", "Да");
                queryParams.Add("miliage", "0");
            }

            // авто старше 2 лет
            if (auto.AutoYearOfIssueValue < DT.Today.Year - 1)
            {
                queryParams.Add("just_transition", "да");
                queryParams.Add("transition", "да");
            }

            // авто не старше 3 лет
            if (auto.AutoYearOfIssueValue > DT.Today.Year - 3)
            {
                queryParams.Add("waranty", "Действует");
            }
        }

        private void AddStaticParams(Dictionary<string, string> queryParams)
        {
            queryParams.Add("owner", "Физическое лицо");
            queryParams.Add("park", "1");
            queryParams.Add("storing", "Свободное хранение");
            queryParams.Add("payment_type", "Единовременно");
            queryParams.Add("period", "12");
            queryParams.Add("insuranse_sum", "Неагрегатная");
        }

        private void AddRegionParam(Deal deal, Dictionary<string, string> queryParams)
        {
            queryParams.Add("city_owner", _calculationMapHelper.CityOfRegistration(deal));
            queryParams.Add("region_owner", _calculationMapHelper.RegionOfRegistration(deal));
            queryParams.Add("city", _calculationMapHelper.CityOfUsing(deal));
            queryParams.Add("region", _calculationMapHelper.RegionOfUsing(deal));
        }

        private string DecimalToString(decimal? value)
        {
            return value.HasValue ? value.Value.ToString("0.##") : string.Empty;
        }
    }
}


# Code\Constructor\CalculationPartner\SendCalculationToPartner\ISendCalculationClient.cs
﻿using iRIS.KaskoLink2.Code.Constructor.CalculationPartner.SendCalculationToPartner.Dtos;

namespace iRIS.KaskoLink2.Code.Constructor.CalculationPartner.SendCalculationToPartner
{
    internal interface ISendCalculationClient
    {
        SendCalculationResponse SendCalculationToPartner(SendCalculationRequest request);
    }
}

# Code\Constructor\CalculationPartner\SendCalculationToPartner\SendCalculationClient.cs
﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using iRIS.Framework.Common.HttpClient;
using iRIS.InsuranceApp.Infrastructure.Helpers;
using iRIS.KaskoLink2.Code.Constructor.CalculationPartner.SendCalculationToPartner.Dtos;
using Microsoft.Extensions.Options;
using Serilog;

namespace iRIS.KaskoLink2.Code.Constructor.CalculationPartner.SendCalculationToPartner
{
    internal class SendCalculationClient : ISendCalculationClient
    {
        private readonly IHttpClient _client;
        private readonly ILogger _logger;
        private readonly KaskoLink2ModuleConfiguration _configuration;

        public SendCalculationClient(IHttpClient client, ILogger logger, IOptions<KaskoLink2ModuleConfiguration> configuration)
        {
            _client = client;
            _logger = logger;
            _configuration = configuration.Value;
        }

        public SendCalculationResponse SendCalculationToPartner(SendCalculationRequest sendCalculationRequest)
        {
            try
            {
                var requestUrl = $"{_configuration.CalculationPartner.SendCalculationToPartnerServiceUrl}";

                var svcCredentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(
                    $"{_configuration.CalculationPartner.SendCalculationToPartnerAuthUser}:{_configuration.CalculationPartner.SendCalculationToPartnerPassword}"));

                var headers = new Dictionary<string, string>
                {
                    {
                        HttpRequestHeader.Authorization.ToString(),
                        "Basic " + svcCredentials
                    }
                };

                var xmlRequest = XmlHelper.ToXml(sendCalculationRequest);

                var response = _client.PerformPut(requestUrl, "application/xml", xmlRequest, headers: headers);

                var xmlResponse = response.Data;
                var sendCalculationResponse = XmlHelper.FromXml<SendCalculationResponse>(xmlResponse);

                _logger.ForContext<SendCalculationClient>()
                    .ForContext("Request", xmlRequest)
                    .ForContext("Response", xmlResponse)
                    .Information("Отправка расчетов в сервис 1С");

                return sendCalculationResponse;
            }
            catch (Exception ex)
            {
                _logger.ForContext<SendCalculationClient>()
                    .ForContext("Request", XmlHelper.ToXml(sendCalculationRequest))
                    .Error(ex, "Ошибка при отправке расчетов в сервис 1С.");

                throw;
            }
        }
    }
}

# Code\Constructor\CalculationPartner\SendCalculationToPartner\SendCalculationRequestCreator.cs
﻿using System.Linq;
using iRIS.Framework.Common;
using iRIS.InsuranceCore.Code.Extensions.Helpers;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Entities.EntityExtensions;
using iRIS.KaskoLink2.Code.Constructor.CalculationPartner.SendCalculationToPartner.Dtos;
using Siebel.Code.Responses;
using Driver = iRIS.KaskoLink2.Code.Constructor.CalculationPartner.SendCalculationToPartner.Dtos.Driver;

namespace iRIS.KaskoLink2.Code.Constructor.CalculationPartner.SendCalculationToPartner
{
    internal class SendCalculationRequestCreator
    {
        private CalculationMapHelper _calculationMapHelper;

        public SendCalculationRequestCreator(CalculationMapHelper calculationMapHelper)
        {
            _calculationMapHelper = calculationMapHelper;
        }

        internal SendCalculationRequest Create(string basketNumber, string requestId, Deal deal, GetQuoteStatusResponse getQuoteStatusResponse)
        {
            var order = new Order
            {
                Id = basketNumber,
                RequestId = requestId,
                Date = DT.Now.ToString("yyyyMMdd"),
                Owner = "Физическое лицо",
                PaymentType = "Единовременно",
                Period = "12",
                InsuranseSum = "Неагрегатная",
                Reason = getQuoteStatusResponse?.Reason,
                Comment = getQuoteStatusResponse?.Comment
            };

            FillPerson(deal, order);
            FillAuto(deal, order);
            FillBank(deal, order);
            FillRegions(deal, order);
            FillDrivers(deal.AutoDeal, order);
            FillConstructor(deal, order);

            return new SendCalculationRequest
            {
                Order = order
            };
        }

        private void FillPerson(Deal deal, Order order)
        {
            var person = deal.Insurant.Subject.IndividualEntity.Person;

            order.Name = person.GetFullName().Trim();
            order.Phone = person.Phone1;
            order.Email = person.Email1;
        }

        private void FillAuto(Deal deal, Order order)
        {
            var auto = deal.GetAuto();
            order.Year = auto.AutoYearOfIssueCode;
            order.Price = DecimalToString(auto.AutoCost);
            order.Mark = auto.AutoBrandName;
            order.Model = auto.AutoModelName;
            order.Power = DecimalToString(auto.AutoEnginePowerValue);
            order.Carbody = auto.AutoBodyType.Name;
            order.Transmission = auto.AutoTransmissionType.Name;
            order.Fuel = auto.AutoEngineType.Name;
            order.EngineCapacity = auto.AutoModification?.AutoEngineValueCode;
            order.Miliage = auto.HasMileage == true && auto.Mileage.HasValue ? auto.Mileage.ToString() : "0";
        }

        private void FillBank(Deal deal, Order order)
        {
            if (deal.GetAuto().IsCreditAuto == true)
            {
                order.Bank = deal.SuggestedBanks.Last().Name;
            }
            else
            {
                order.Bank = string.Empty;
            }
        }

        private void FillRegions(Deal deal, Order order)
        {
            order.City = _calculationMapHelper.CityOfUsing(deal);
            order.Region = _calculationMapHelper.RegionOfUsing(deal);
            order.CityOwner = _calculationMapHelper.CityOfRegistration(deal);
            order.RegionOwner = _calculationMapHelper.RegionOfRegistration(deal);
        }

        private void FillDrivers(AutoDeal autoDeal, Order order)
        {
            if (autoDeal.IsMultidrive != true)
            {
                order.Drivers.AddRange(autoDeal.Drivers.Select(x => new Driver
                {
                    Age = x.Subject.IndividualEntity.Person.Age.ToString(),
                    Experience = x.DrivingExperiences.First().FullDrivingExperience.ToString()
                }));
            }
            else
            {
                order.AcceptedDrivers = "Неограниченное количество";
                order.MinAge = "18";
                order.MinExp = "0";
            }
        }

        private void FillConstructor(Deal deal, Order order)
        {
            var dealHelper = new DealHelper(deal);
            order.Compensation = _calculationMapHelper.Compensation(dealHelper);
            order.Franshrur = DecimalToString(_calculationMapHelper.Franchise(dealHelper));
        }

        private string DecimalToString(decimal? value)
        {
            return value.HasValue ? value.Value.ToString("0.##") : string.Empty;
        }
    }
}


# Code\Constructor\CalculationPartner\SendCalculationToPartner\Dtos\Driver.cs
﻿using System.Xml.Serialization;

namespace iRIS.KaskoLink2.Code.Constructor.CalculationPartner.SendCalculationToPartner.Dtos
{
    public class Driver
    {
        [XmlElement("age")]
        public string Age { get; set; }

        [XmlElement("experience")]
        public string Experience { get; set; }
    }
}


# Code\Constructor\CalculationPartner\SendCalculationToPartner\Dtos\Order.cs
﻿using System.Collections.Generic;
using System.Xml.Serialization;

namespace iRIS.KaskoLink2.Code.Constructor.CalculationPartner.SendCalculationToPartner.Dtos
{
    public class Order
    {
        [XmlElement("id")]
        public string Id { get; set; }

        [XmlElement("date")] 
        public string Date { get; set; }

        [XmlElement("name")] 
        public string Name { get; set; }

        [XmlElement("email")] 
        public string Email { get; set; }
/// <summary>
        /// Расчет окончательного КВ: 
        /// если основной посредник работает с компенсацией, то рассчитать окончательное КВ по формуле: КВ% = ((КВ% - Скидка%) / (100% - Скидка%)) * 100.
        /// если основной посредник работает без компенсации, то рассчитать окончательное КВ по формуле: КВ% = КВ% - Скидка%.
        /// </summary>
        private void ApplyRequestedDiscountToMainIntermediary(DealIntermediary dealIntermediary, decimal requestedDiscountCommission)
        {
            if (dealIntermediary.Intermediary.WorkWithCompensation == true)
            {
                var cv = (dealIntermediary.CommisionValue - requestedDiscountCommission) / (100 - requestedDiscountCommission) * 100;
                dealIntermediary.CommisionValue = Math.Round(cv.Value, 2);
            }
            else
            {
                dealIntermediary.CommisionValue -= requestedDiscountCommission;
            }
        }

        /// <summary>
        /// Превышает ли размер скидки, присланный партнером, CommisionValue посредника с IsMain.
        /// </summary>
        private bool IsRequestedKvDiscountGreater(DealIntermediary dealIntermediary, decimal requestedDiscountCommission)
        {
            return requestedDiscountCommission > dealIntermediary.CommisionValue.Value;
        }

        /// <summary>
        /// Установка нулевого КВ в случае отсутствия ответа от АИС.
        /// </summary>
        private void SetZeroCommissionDiscount(Deal deal)
        {
            var mainIntermediary = deal.DealIntermediaries.Single(di => di.IsMain == true);
            mainIntermediary.CommisionValue = 0;
        }

        private void InitializeCustomProcessVariables(IProcessContext processContext)
        {
            _basketNumber = BasketNumber.Get(processContext);
            _useDrafts = UseDrafts.Get(processContext);
            _deals = Deals.Get(processContext);
            _authorizationData = AuthorizationData.Get(processContext);
            _requestedCommissionDiscount = processContext.GetCustomVariable("CommissionDiscount")?.ToString();

            _dictionariesCacheManager = processContext.ServiceProvider.GetRequiredService<IDictionariesCacheManager>();
            _aisIntegrationClient = processContext.ServiceProvider.GetRequiredService<IAisIntegrationClient>();
            _aisProductGetter = processContext.ServiceProvider.GetRequiredService<IAISProductGetter>();
            _logger = processContext.ServiceProvider.GetRequiredService<ILogger>().ForContext<GetKaskoCommissionsWithSegmentProcess>();
            _actualizeDealIntermediary = processContext.ServiceProvider.GetRequiredService<IActualizeDealIntermediary>();
            _validationResultsAggregator = processContext.ServiceProvider.GetRequiredService<IValidationResultsAggregator>();
        }

        private void LogProcessStart()
        {
            _logger
                .ForContext("ProcessKey", _basketNumber)
                .Information($"Запуск процесса {nameof(GetKaskoCommissionsWithSegmentProcess)} получения КВ для посредников сделок.");
        }
    }
}

# Code\CustomProcesses\GetRecalculationChangesCustomProcess.cs
﻿using System;
using iRIS.Framework.Workflow.Process.CustomProcessModel;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Entities.EntityExtensions;
using iRIS.KaskoLink2.Code.Implementations.Comparison;
using Microsoft.Extensions.DependencyInjection;
using Serilog;

namespace iRIS.KaskoLink2.Code.CustomProcesses
{
    public sealed class GetRecalculationChangesCustomProcess : ICustomProcess
    {
        public const string InputArgument_ExpectedBasket = nameof(ExpectedBasket);
        public const string InputArgument_ActualBasket = nameof(ActualBasket);
        public const string OutputArgument_Changes = nameof(Changes);

        /// <summary>
        /// Входной параметр - исходная корзина.
        /// </summary>
        /// <input/>
        public InputArgument<Basket> ExpectedBasket { get; } = new InputArgument<Basket>(InputArgument_ExpectedBasket);

        /// <summary>
        /// Входной параметр - текущая корзина.
        /// </summary>
        /// <input/>
        public InputArgument<Basket> ActualBasket { get; } = new InputArgument<Basket>(InputArgument_ActualBasket);

        /// <summary>
        /// Выходной параметр - словарь ченджей.
        /// </summary>
        /// <output/>
        public OutputArgument<ChangesWrapper> Changes { get; } = new OutputArgument<ChangesWrapper>(OutputArgument_Changes);

        public void Execute(IProcessContext processContext)
        {
            var log = processContext.ServiceProvider.GetService<ILogger>().ForContext<GetRecalculationChangesCustomProcess>();
            log.Information("Перерасчет. Блок получения ченджей");

            try
            {
                var expectedBasket = ExpectedBasket.Get(processContext);
                var actualBasket = ActualBasket.Get(processContext);

                if (expectedBasket == null)
                {
                    return;
                }

                var expectedDeal = expectedBasket.GetKaskoDeal();
                var actualDeal = actualBasket.GetKaskoDeal();

                var dealComparer = (ObjectComparer<Deal>)ObjectComparerBuilder.CreateDealComparer(processContext.ServiceProvider);
                var changes = dealComparer.GetChanges(expectedDeal, actualDeal);

                Changes.Set(processContext, new ChangesWrapper { ChangesDictionary = changes });
            }
            catch (Exception ex)
            {
                log.Error(ex, "Произошла ошибка в блоке получения ченджей при перерасчете");
                throw;
            }
        }
    }
}

# Code\CustomProcesses\InitializeVersionAutoDictionaryClientProcess.cs
﻿using iRIS.Framework.Workflow.Process.CustomProcessModel;
using iRIS.Framework.Workflow.UserData;
using iRIS.InsuranceCore.Code.Helpers;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Infrastructure.Constants;
using System.Collections.Generic;
using iRIS.Framework.Entity.Dictionary.ABTests;
using Microsoft.Extensions.DependencyInjection;
using iRIS.Framework.Entity.Dictionary.EntitySettings;
using System;
using System.Linq;
using iRIS.KaskoLink2.Code.CreateOn.ProcessApi.Prolongation;
using iRIS.KaskoLink2.Implementations.Code.Implementations.AutoDictionary;

namespace iRIS.KaskoLink2.Code.CustomProcesses
{
    public class InitializeVersionAutoDictionaryClientProcess : ICustomProcess
    {
        private const string _userKaskoUpsale = "IrisKaskoUser@renins.com";
        private const string _autoDictClientVer2Enabled = "KaskoAutoDictClientVer2Enabled";
        private const string _processApiCommandNameKey = "ProcessApiCommandName";

        /// <input/>
        public const string AuthorizationData = nameof(AuthorizationData);

        /// <input/>
        public const string Basket = nameof(Basket);

        /// <input/>
        public const string IsCreateProcess = nameof(IsCreateProcess);

        /// <summary>
        /// При добавлении новых исключений обращаться в команду ФК5 (Безднежных Николай, Саймуков Дмитрий).
        /// </summary>
        private static readonly IReadOnlyList<AutoDictionaryClientVerConditions> _conditions = new List<AutoDictionaryClientVerConditions>()
        {
            new AutoDictionaryClientVerConditions((u, ugs, _) => ugs.Any(ug => new[] { UserGroups.Link2Agents, UserGroups.Link2DiAgents }.Contains(ug)) && u != _userKaskoUpsale, AutoDictionaryClientResolver.AbTestVariantV2),
            new AutoDictionaryClientVerConditions((u, ugs, _) => ugs.Contains(UserGroups.Link2Agents) && u == _userKaskoUpsale, AutoDictionaryClientResolver.AbTestVariantV1),
            new AutoDictionaryClientVerConditions((_, ugs, _) => ugs.Contains(UserGroups.CallCenter), AutoDictionaryClientResolver.AbTestVariantV1),
            new AutoDictionaryClientVerConditions((_, _, cnt) => cnt.GetCustomVariable(_processApiCommandNameKey)?.ToString() == DiKaskoInsuranceProlongationCommand.CommandName, AutoDictionaryClientResolver.AbTestVariantV1),
            new AutoDictionaryClientVerConditions((_, _, cnt) => cnt.GetCustomVariable(_processApiCommandNameKey)?.ToString() == DiKaskoInsuranceCreateOnCommand.CommandName, AutoDictionaryClientResolver.AbTestVariantV1)
        };

        private readonly InputArgument<Basket> _basket = new InputArgument<Basket>(Basket);
        private readonly InputArgument<AuthorizationData> _authorizationData = new InputArgument<AuthorizationData>(AuthorizationData);
        private readonly InputArgument<bool> _isCreateProcess = new InputArgument<bool>(IsCreateProcess);

        public void Execute(IProcessContext processContext)
        {
            var abTestManager = processContext.ServiceProvider.GetRequiredService<IABTestsManager>();
            var entitySettingsManager = processContext.ServiceProvider.GetRequiredService<IEntitySettingsManager>();

            var basket = _basket.GetDefaultIfEmpty(processContext);
            var authorizationData = _authorizationData.GetDefaultIfEmpty(processContext);
            var isCreateProcess = _isCreateProcess.GetDefaultIfEmpty(processContext);

            var clientVer2Enabled = entitySettingsManager.GetSettingValue<bool>(_autoDictClientVer2Enabled);
            var variantByAbTest = abTestManager.GetAppliedTestVariant(AutoDictionaryClientResolver.AbTestTypeCode);

            // Если создаем процесс и 2ая версия клиента справочника авто не доступна -> не будем инициализировать AB тест
            if (isCreateProcess && !clientVer2Enabled)
            {
                return;
            }

            // Если возобновляем существующий процесс и ранее не инициализировали Ab тест -> не будем инициализировать AB тест
            if (!isCreateProcess && string.IsNullOrEmpty(variantByAbTest))
            {
                return;
            }

            var userGroups = UserRoleHelper.GetUserGroups(authorizationData, processContext);
            var availableVariantsAbTest = new List<string>() { AutoDictionaryClientResolver.AbTestVariantV1, AutoDictionaryClientResolver.AbTestVariantV2 };

            foreach (var cnd in _conditions)
            {
                if (cnd.Func(authorizationData.Name, userGroups, processContext))
                {
                    availableVariantsAbTest.Remove(cnd.ExcludeVariant);
                }
            }

            if (!availableVariantsAbTest.Contains(variantByAbTest))
            {
                abTestManager.InitializeProcessTest(AutoDictionaryClientResolver.AbTestTypeCode, AutoDictionaryClientResolver.ProcessTypeName, basket.Number, availableVariantsAbTest);
            }
        }

        private class AutoDictionaryClientVerConditions
        {
            public Func<string, IEnumerable<string>, IProcessContext, bool> Func { get; set; }

            public string ExcludeVariant { get; set; }

            public AutoDictionaryClientVerConditions(Func<string, IEnumerable<string>, IProcessContext, bool> func, string excludeVariant)
            {
                Func = func;
                ExcludeVariant = excludeVariant;
            }
        }
    }
}


# Code\CustomProcesses\KaskoCheckUrmIncreaseCustomProcess.cs
﻿using iRIS.Framework.CrossCutting.Caching;
using iRIS.Framework.RequestPipeline.Extensions;
using iRIS.Framework.Workflow.Process.CustomProcessModel;
using iRIS.Framework.Workflow.UserData;
using iRIS.InsuranceCore.Code.Helpers;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Infrastructure.Constants;
using iRIS.KaskoCore.Code.Extensions;
using iRIS.KaskoLink2.Code.Constants;
using iRIS.KaskoLink2.Code.TypeExtensions;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;

namespace iRIS.KaskoLink2.Code.CustomProcesses
{
    /// <summary>
    /// Проверка был ли выставлен коэффициент УРМ.
    /// </summary>
    public sealed class KaskoCheckUrmIncreaseCustomProcess : ICustomProcess
    {
        /// <branch/>
        public const string ExitBranch_UrmIncreaseFlag = "UrmIncreaseFlag";

        /// <branch/>
        public const string ExitBranch_Default = "Default";

        /// <summary>
        /// Корзина.
        /// </summary>
        public const string InputArgument_Basket = nameof(Basket);

        public const string InputArgumentAuthorizationData = nameof(AuthorizationData);

        /// <summary>
        /// Корзина.
        /// </summary>
        public InputArgument<Basket> Basket { get; } = new InputArgument<Basket>(InputArgument_Basket);

        private readonly InputArgument<AuthorizationData> _authorizationData = new InputArgument<AuthorizationData>(InputArgumentAuthorizationData);

        public void Execute(IProcessContext processContext)
        {
            var exitBranch = ExitBranch_Default;
            var context = processContext.ServiceProvider.GetService<PipelineExecutionContext>();
            var cache = processContext.ServiceProvider.GetService<ICache>();
            var basket = Basket.GetDefaultIfEmpty(processContext);
            var key = $"{DiKaskoQuestionnaireProcessVariablesKeys.DiKaskoQuestionnaireStepRecalculationIsNeededAfterUrmChanged}_{basket.Number}";
            var isUrmChanged = cache.Get<bool?>(key);

            var userGroups = new List<string>();
            if (_authorizationData.TryGet(processContext, out var authorizationData))
            {
                userGroups = UserRoleHelper.GetUserGroups(authorizationData, processContext).ToList();
            }

            if (userGroups.Contains(UserGroups.CallCenter))
            {
                if (isUrmChanged.HasValue && isUrmChanged.Value && basket.HasKasko())
                {
                    exitBranch = ExitBranch_UrmIncreaseFlag;
                }
            }

            processContext.SetExitBranch(exitBranch);
        }
    }
}


# Code\CustomProcesses\KaskoCheckUserGroupProcess.cs
﻿using iRIS.Framework.Workflow.Process.CustomProcessModel;
using iRIS.Framework.Workflow.UserData;
using iRIS.InsuranceCore.Code.Helpers;
using iRIS.InsuranceCore.Infrastructure.Constants;
using System;
using System.Collections.Generic;
using System.Linq;

namespace iRIS.KaskoLink2.Code.CustomProcesses
{
    /// <summary>
    /// Проверка групп текущего пользователя.
    /// </summary>
    public class KaskoCheckUserGroupProcess : ICustomProcess
    {
        /// <input/>
        public const string InputArgumentAuthorizationData = nameof(AuthorizationData);

        /// <branch/>
        public const string ExitBranch_AdminOrHelpDesk = "AdminOrHelpDesk";

        /// <branch/>
        public const string ExitBranch_DocReviewer = "DocReviewer";

        /// <branch/>
        public const string ExitBranch_SystemDIUser = "SystemDIUser";

        /// <branch/>
        public const string ExitBranch_Clients = "Clients";

        /// <branch/>
        public const string ExitBranch_CallCenter = "CallCenter";

        /// <branch/>
        public const string ExitBranch_Delivery = "Delivery";

        /// <branch/>
        public const string ExitBranch_URM = "URM";

        /// <branch/>
        public const string ExitBranch_DIUnderwriter = "DIUnderwriter";

        /// <branch/>
        public const string ExitBranch_Link2Agents = "Link2Agents";

        /// <branch/>
        public const string ExitBranch_AgentOrSeller = "AgentOrSeller";

        /// <branch/>
        public const string ExitBranch_ServiceCallCenter = "ServiceCallCenter";

        /// <branch/>
        public const string ExitBranch_Anonymous = "Anonymous";

        /// <branch/>
        public const string ExitBranch_Default = "Default";

        private readonly InputArgument<AuthorizationData> _inputArgumentAuthorizationData = new InputArgument<AuthorizationData>(InputArgumentAuthorizationData);
Где устанавливаются ограничения по сумме франшиз в зависимости от определенных условий?