Отвечай на вопросы, используя следующий контекст:
/// <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;
# Code\AutoProlongation\Implementations\KaskoAutoProlongationLogMessageTemplateGetter.cs
﻿using iRIS.KaskoCore.AutoProlongation.Code.Interfaces;
using iRIS.KaskoCore.AutoProlongation.Code.Model;

namespace iRIS.KaskoLink2.Code.AutoProlongation.Implementations
{
    internal class KaskoAutoProlongationLogMessageTemplateGetter : IKaskoAutoProlongationLogMessageTemplateGetter
    {
        private const string _prolongationErrorTemplate = "Пролонгация полиса завершилась с ошибкой.";
        private const string _kaskoBasedOnEosagoErrorTemplate = "Создание лида завершилось с ошибкой.";
        private const string _prolongationSuccessTemplate = "Пролонгация полиса завершилась успешно.";
        private const string _kaskoBasedOnEosagoSuccessTemplate = "Создание лида завершилось успешно.";
        private const string _kaskoUpsalesToOssSuccessTemplate = "Отправка полиса напрямую в ОСС завершилась успешно";
        private const string _kaskoUpsalesToOssErrorTemplate = "Отправка полиса напрямую в ОСС завершилась с ошибкой";
        private const string _kaskoRopTemplate = "Создание ROP активности завершилась успешно";
        private const string _kaskoRopErrorTemplate = "Создание ROP активности завершилась с ошибкой";

        public string GetMessageTemplate(KaskoAutoProlongationMessage autoProlongationMessage, bool isError)
        {
            return autoProlongationMessage switch
            {
                { IsKaskoBasedOnEosago: true } when isError == true => _kaskoBasedOnEosagoErrorTemplate,
                { IsKaskoBasedOnEosago: true } when isError == false => _kaskoBasedOnEosagoSuccessTemplate,
                { IsKaskoUpsalesToOss: true } when isError == true => _kaskoUpsalesToOssErrorTemplate,
                { IsKaskoUpsalesToOss: true } when isError == false => _kaskoUpsalesToOssSuccessTemplate,
                { IsRop: true } when isError == true => _kaskoRopErrorTemplate,
                { IsRop: true } when isError == false => _kaskoRopTemplate,
                { IsKaskoBasedOnEosago: false } when isError == true => _prolongationErrorTemplate,
                { IsKaskoBasedOnEosago: false } when isError == false => _prolongationSuccessTemplate
            };
        }
    }
}


# Code\AutoProlongation\Implementations\KaskoAutoProlongationPackageGetter.cs
﻿using iRIS.Framework.Entity.Dictionary.EntitySettings;
using iRIS.InsuranceCore.OSS.Code.ClientWrappers.GetPolicyProlongation;
using iRIS.InsuranceCore.OSS.Code.ClientWrappers.GetPolicyProlongation.RequestResponse;
using iRIS.KaskoCore.AutoProlongation.Code.Implementations;
using iRIS.KaskoCore.AutoProlongation.Code.Model;
using iRIS.KaskoLink2.Code.Queries;
using iRIS.KaskoLink2.Code.TypeExtensions;
using iRIS.KaskoLink2.Entities;
using System;
using System.Collections.Generic;
using System.Linq;

namespace iRIS.KaskoLink2.Code.AutoProlongation.Implementations
{
    /// <inheritdoc />
    internal class KaskoAutoProlongationPackageGetter : BaseKaskoAutoProlongationPackageGetter
    {
        private readonly IQueryOsagoProlongationClientType _queryOsagoProlongationClientType;
        private IReadOnlyCollection<string> _osagoFilterChannelCodes = new[] { "SRL08009", "SRL00777", "SRL08005", "SRL08004" };

        /// <summary>
        /// Initializes a new instance of the <see cref="KaskoAutoProlongationPackageGetter"/> class.
        /// </summary>
        /// <param name="ossGetPolicyProlongation">Осс врапер пролангационных полисов.</param>
        /// <param name="entitySettingsManager">Менедженр настроек пролонгации.</param>
        /// <param name="queryOsagoProlongationClientType">Менеджер данных сегментирования пролонгации чистого ОСАГО</param>
        public KaskoAutoProlongationPackageGetter(
            IOssGetPolicyProlongationWrapper ossGetPolicyProlongation,
            IEntitySettingsManager entitySettingsManager,
            IQueryOsagoProlongationClientType queryOsagoProlongationClientType)
            : base(ossGetPolicyProlongation, entitySettingsManager)
        {
            _queryOsagoProlongationClientType = queryOsagoProlongationClientType;
        }

        private OsagoProlongationClientType GetOsagoProlongationClientType(string policyNumber, DateTime presentDay)
         => _queryOsagoProlongationClientType
            .GetOsagoProlongationClientTypesByDate(presentDay)
            ?.TryGetValue(policyNumber, out var type) ?? false ? type : null;

        protected override bool GetClientTypeCode(PolicyGroupDto policy, DateTime presentDay, bool isValidFilterContext, out string clientTypeCode)
        {
            var osagoProlongationClientType = isValidFilterContext && policy.IsClearOsaga() ? GetOsagoProlongationClientType(policy.Policies.FirstOrDefault().PolicyNumber, presentDay) : null;

            clientTypeCode = null;

            if (isValidFilterContext && policy.IsClearOsaga() && osagoProlongationClientType == null)
            {
                return false;
            }

            clientTypeCode = osagoProlongationClientType?.ClientTypeCode;

            return true;
        }

        protected override bool IsValidFilterContext(KaskoAutoProlongationPrepareSetting setting, DateTime presentDay)
        {
            return _osagoFilterChannelCodes.Any(code => setting.ChannelCodes?.Contains(code) ?? false) && presentDay <= _queryOsagoProlongationClientType.GetLastDate();
        }
    }
}   


# Code\AutoProlongation\Implementations\KaskoAutoProlongationPackageReport.cs
﻿using iRIS.Framework.Entity.Dictionary.EntitySettings;
using iRIS.InsuranceCore;
using iRIS.InsuranceCore.Entities;
using Serilog;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using iRIS.KaskoLink2.Code.AutoProlongation.Constants;
using iRIS.KaskoLink2.Code.AutoProlongation.Helpers;
using iRIS.KaskoCore.AutoProlongation.Code.Implementations;
using iRIS.KaskoCore.AutoProlongation.Code.Model;
using iRIS.KaskoCore.AutoProlongation.Code.Interfaces;
using EmailClient.Code.Interfaces;
using iRIS.KaskoCore.Code.Helpers;

namespace iRIS.KaskoLink2.Code.AutoProlongation.Implementations
{
    internal class KaskoAutoProlongationPackageReport : BaseKaskoAutoProlongationPackageReport, IKaskoAutoProlongationPackageReport
    {
        public KaskoAutoProlongationPackageReport(
            IEmailClient emailClient,
            IEntitySettingsManager entitySettingsManager,
            IOptions<InsuranceCoreModuleConfiguration> configuration,
            ILogger logger)
            : base(emailClient, entitySettingsManager, configuration, logger)
        {
        }

        protected override string ErrorMessage => "Ошибка отправки отчета по автопролонгации.";

        public async Task SendPackageReportAsync(AutoProlongationPackage package)
        {
            await base.SendPackageReportAsync(package);
        }

        protected override string BuildMailBody(AutoProlongationPackage package)
        {
            return BuildMailHelper.BuildMailBody(package, BuildMailHelper.CreateTable);
        }

        protected override string BuildMailSubject(AutoProlongationPackage package, InsuranceCoreModuleConfiguration configuration)
        {
            return $"[{KaskoReportHelper.GetEnvironment(configuration)}_IRIS] Завершение процесса автопролонгации договоров {package.Description}.";
        }

        protected override KaskoAutoProlongationReportSetting GetReportSetting(IEntitySettingsManager entitySettingsManager)
        {
           return entitySettingsManager.GetSettingValue<KaskoAutoProlongationReportSetting>(ReportSetting.KaskoAutoProlongationReportSetting);
        }
    }
}


# Code\AutoProlongation\Implementations\KaskoAutoProlongationPartnerPackageReport.cs
﻿using iRIS.Framework.Entity.Dictionary.EntitySettings;
using iRIS.InsuranceCore;
using iRIS.InsuranceCore.Entities;
using iRIS.KaskoLink2.Code.AutoProlongation.Interfaces;
using Serilog;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using iRIS.KaskoLink2.Code.AutoProlongation.Constants;
using iRIS.KaskoLink2.Code.AutoProlongation.Helpers;
using iRIS.KaskoCore.AutoProlongation.Code.Implementations;
using iRIS.KaskoCore.AutoProlongation.Code.Model;
using EmailClient.Code.Interfaces;
using iRIS.KaskoCore.Code.Helpers;

namespace iRIS.KaskoLink2.Code.AutoProlongation.Implementations
{
    internal class KaskoAutoProlongationPartnerPackageReport : BaseKaskoAutoProlongationPackageReport, IKaskoProlongationPartnerPackageReport
    {
        public KaskoAutoProlongationPartnerPackageReport(
            IEmailClient emailClient,
            IEntitySettingsManager entitySettingsManager,
            IOptions<InsuranceCoreModuleConfiguration> configuration,
            ILogger logger)
            : base(emailClient, entitySettingsManager, configuration, logger)
        {
        }

        protected override string ErrorMessage => "Ошибка отправки отчета по автопролонгации партнерских полисов.";

        public async Task SendPackageReportAsync(AutoProlongationPackage package)
        {
            await base.SendPackageReportAsync(package);
        }

        protected override string BuildMailBody(AutoProlongationPackage package)
        {
            return BuildMailHelper.BuildMailBody(package, BuildMailHelper.CreateTable);
        }

        protected override string BuildMailSubject(AutoProlongationPackage package, InsuranceCoreModuleConfiguration configuration)
        {
            return $"[{KaskoReportHelper.GetEnvironment(configuration)}_IRIS] Завершение процесса автопролонгации договоров {package.Description}.";
        }

        protected override KaskoAutoProlongationReportSetting GetReportSetting(IEntitySettingsManager entitySettingsManager)
        {
           return entitySettingsManager.GetSettingValue<KaskoAutoProlongationReportSetting>(ReportSetting.KaskoProlongationPartnerReportSetting);
        }
    }
}


# Code\AutoProlongation\Implementations\KaskoAutoProlongationReportGenerator.cs
﻿using iRIS.InsuranceCore.Entities;
using iRIS.KaskoCore.AutoProlongation.Code.Interfaces;
using iRIS.KaskoCore.AutoProlongation.Code.Model;
using iRIS.KaskoCore.Code.Helpers;
using iRIS.KaskoLink2.Code.AutoProlongation.Interfaces;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace iRIS.KaskoLink2.Code.AutoProlongation.Implementations
{
    internal class KaskoAutoProlongationReportGenerator : IKaskoAutoProlongationReportGenerator
    {
        private readonly IKaskoAutoProlongationPackageReport _packageReport;
        private readonly IKaskoAutoProlongationDataReport _dataReport;
        private readonly IKaskoSubscriptionPackageReport _kaskoSubscriptionPackageReport;
        private readonly IKaskoBasedOnEosagoPackageReport _kaskoBasedOnEosagoPackageReport;
        private readonly IKaskoProlongationPartnerPackageReport _kaskoProlongationPartnerPackageReport;
        private readonly IKaskoUpsalesToOssPackageReport _kaskoUpsalesToOssPackageReport;
        private readonly IKaskoRopPackageReport _kaskoRopPackageReport;
        private readonly IOsagoSegmentationExpireNotifier _osagoSegmentationExpireNotifier;

        public KaskoAutoProlongationReportGenerator(
            IKaskoAutoProlongationPackageReport packageReport,
            IKaskoAutoProlongationDataReport prevDataReport,
            IKaskoSubscriptionPackageReport kaskoSubscriptionPackageReport,
            IKaskoBasedOnEosagoPackageReport kaskoBasedOnEosagoPackageReport,
            IKaskoProlongationPartnerPackageReport kaskoProlongationPartnerPackageReport,
            IKaskoUpsalesToOssPackageReport kaskoUpsalesToOssPackageReport,
            IKaskoRopPackageReport kaskoRopPackageReport,
            IOsagoSegmentationExpireNotifier osagoSegmentationExpireNotifier)
        {
            _packageReport = packageReport ?? throw new ArgumentNullException(nameof(_packageReport));
            _dataReport = prevDataReport ?? throw new ArgumentNullException(nameof(_dataReport));
            _kaskoSubscriptionPackageReport = kaskoSubscriptionPackageReport ?? throw new ArgumentNullException(nameof(_kaskoSubscriptionPackageReport));
            _kaskoBasedOnEosagoPackageReport = kaskoBasedOnEosagoPackageReport ?? throw new ArgumentNullException(nameof(_kaskoBasedOnEosagoPackageReport));
            _kaskoProlongationPartnerPackageReport = kaskoProlongationPartnerPackageReport ?? throw new ArgumentNullException(nameof(_kaskoProlongationPartnerPackageReport));
            _kaskoUpsalesToOssPackageReport = kaskoUpsalesToOssPackageReport ?? throw new ArgumentNullException(nameof(_kaskoUpsalesToOssPackageReport));
            _kaskoRopPackageReport = kaskoRopPackageReport ?? throw new ArgumentNullException(nameof(_kaskoRopPackageReport));
            _osagoSegmentationExpireNotifier = osagoSegmentationExpireNotifier ?? throw new ArgumentNullException(nameof(_osagoSegmentationExpireNotifier));
        }

        public async Task GenerateReportAsync(AutoProlongationPackage package)
        {
            var kaskoAutoProlongationMessage = GetKaskoAutoProlongationMessage(package);
            if (IsSubscription(kaskoAutoProlongationMessage))
            {
                await _kaskoSubscriptionPackageReport.SendPackageReportAsync(package);
            }
            else if (IsKaskoBasedOnEosago(kaskoAutoProlongationMessage))
            {
                await _kaskoBasedOnEosagoPackageReport.SendPackageReportAsync(package);
            }
            else if (IsProlongationPartner(kaskoAutoProlongationMessage))
            {
                await _kaskoProlongationPartnerPackageReport.SendPackageReportAsync(package);
            }
            else if (IsKaskoUpsalesToOss(kaskoAutoProlongationMessage))
            {
                await _kaskoUpsalesToOssPackageReport.SendPackageReportAsync(package);
            }
            else if (IsKaskoRop(kaskoAutoProlongationMessage))
            {
                await _kaskoRopPackageReport.SendPackageReportAsync(package);
            }
            else
            {
                var packageReportTask = _packageReport.SendPackageReportAsync(package);
                var dataReportTask = _dataReport.SendDataReportAsync(package);
                var segmentationExpireNotifierTask = _osagoSegmentationExpireNotifier.SendNotificationAsync();

                await Task.WhenAll(packageReportTask, dataReportTask, segmentationExpireNotifierTask);
            }
        }

        private bool IsSubscription(KaskoAutoProlongationMessage kaskoAutoProlongationMessage)
        {
            return kaskoAutoProlongationMessage?.IsSubscription == true;
        }

        private bool IsKaskoBasedOnEosago(KaskoAutoProlongationMessage kaskoAutoProlongationMessage)
        {
            return kaskoAutoProlongationMessage?.IsKaskoBasedOnEosago == true;
        }

        private bool IsProlongationPartner(KaskoAutoProlongationMessage kaskoAutoProlongationMessage)
        {
            return kaskoAutoProlongationMessage?.IsProlongationPartner == true;
        }

        private bool IsKaskoUpsalesToOss(KaskoAutoProlongationMessage kaskoAutoProlongationMessage)
        {
            return kaskoAutoProlongationMessage?.IsKaskoUpsalesToOss == true;
        }

        private bool IsKaskoRop(KaskoAutoProlongationMessage kaskoAutoProlongationMessage)
        {
            return kaskoAutoProlongationMessage?.IsRop == true;
        }

        private KaskoAutoProlongationMessage GetKaskoAutoProlongationMessage(AutoProlongationPackage package)
        {
            if (package.AutoProlongationPolicies.Any())
            {
                var autoProlongationMessage = KaskoAutoProlongationHelper.GetKaskoAutoProlongationMessage(package.AutoProlongationPolicies.First().Message);
                return autoProlongationMessage;
            }

            return null;
        }
    }
}
/// <summary>
        /// Проверка наличия андеррайтинга в сделке.
        /// </summary>
        /// <param name="basket"></param>
        /// <returns></returns>
        public bool IsUnderwritingCompleted(Basket basket)
        {
            var underwritingApprovals = basket.GetKaskoDeal().AutoDeal.DIUnderwriterApprovals;

            return underwritingApprovals?.All(underwritingApproval =>
                    underwritingApproval.StatusCode == DiUnderwriterApprovalStatusCodes.Accepted) == true;
        }

        /// <summary>
        /// Проверки андеррайтинга не добавлены.
        /// </summary>
        /// <param name="basket"></param>
        /// <returns></returns>
        public bool IsNoUnderwriting(Basket basket)
        {
            var underwritingApprovals = basket.GetKaskoDeal().AutoDeal.DIUnderwriterApprovals;

            return underwritingApprovals == null || underwritingApprovals.Count == 0;
        }

        /// <summary>
        /// Проверки андеррайтинга добавлены и не завершены.
        /// </summary>
        /// <param name="basket"></param>
        /// <returns></returns>
        public bool IsUnderwritingAddedAndNotCompleted(Basket basket)
        {
            var underwritingApprovals = basket.GetKaskoDeal().AutoDeal.DIUnderwriterApprovals;

            return underwritingApprovals?.Any(underwritingApproval =>
                    underwritingApproval.StatusCode == DiUnderwriterApprovalStatusCodes.Required ||
                    underwritingApproval.StatusCode == DiUnderwriterApprovalStatusCodes.InWork) == true;
        }

        #endregion

        #region ota

        /// <summary>
        /// Проверка наличия ОТА в сделке.
        /// </summary>
        /// <param name="basket"></param>
        /// <returns></returns>
        public bool IsOtaCompleted(Basket basket)
        {
            var otaApprovals = basket.GetKaskoDeal().AutoDeal.OtaApproval;

            return otaApprovals?.All(otaApproval =>
                    otaApproval.OtaApprovalStatusCode == OtaApprovalStatusCodes.NoMistakes
                    || otaApproval.OtaApprovalStatusCode == OtaApprovalStatusCodes.NonCriticalMistakes) == true;
        }

        /// <summary>
        /// Проверки ОТА не добавлены.
        /// </summary>
        /// <param name="basket"></param>
        /// <returns></returns>
        public bool IsNoOta(Basket basket)
        {
            var otaApprovals = basket.GetKaskoDeal().AutoDeal.OtaApproval;

            return otaApprovals == null || otaApprovals.Count == 0;
        }

        /// <summary>
        /// Проверки ОТА добавлены и не завершены.
        /// </summary>
        /// <param name="basket"></param>
        /// <returns></returns>
        public bool IsOtaAddedAndNotCompleted(Basket basket)
        {
            var otaApprovals = basket.GetKaskoDeal().AutoDeal.OtaApproval;

            return otaApprovals?.Any(otaApproval =>
                    otaApproval.OtaApprovalStatusCode == OtaApprovalStatusCodes.InWork
                    || otaApproval.OtaApprovalStatusCode == OtaApprovalStatusCodes.Required) == true;
        }

        #endregion

        #region urm

        /// <summary>
        /// Проверка наличия урм в сделке.
        /// </summary>
        /// <param name="basket"></param>
        /// <returns></returns>
        public bool IsUrmCompleted(Basket basket)
        {
            var urmApprovals = basket.GetKaskoDeal().AutoDeal.URMApproval;

            return urmApprovals?.All(urmapproval =>
                    urmapproval.URMApprovalStatusCode == UrmApprovalStatusCodes.Accepted
                    || urmapproval.URMApprovalStatusCode == UrmApprovalStatusCodes.AcceptedWithLimits) == true;
        }

        /// <summary>
        /// Проверки УРМ не добавлены.
        /// </summary>
        /// <param name="basket"></param>
        /// <returns></returns>
        public bool IsNoUrm(Basket basket)
        {
            var urmApprovals = basket.GetKaskoDeal().AutoDeal.URMApproval;

            return urmApprovals == null || urmApprovals.Count == 0;
        }

        /// <summary>
        /// Проверки УРМ добавлены и не завершены.
        /// </summary>
        /// <param name="basket"></param>
        /// <returns></returns>
        public bool IsUrmAddedAndNotCompleted(Basket basket)
        {
            var urmApprovals = basket.GetKaskoDeal().AutoDeal.URMApproval;

            return urmApprovals?.Any(urmApproval =>
                    urmApproval.URMApprovalStatusCode == UrmApprovalStatusCodes.Required ||
                    urmApproval.URMApprovalStatusCode == UrmApprovalStatusCodes.RequiredExtraInfo) == true;
        }

        #endregion

        /// <summary>
        /// Доступна ли навигация по процессу проверки статусов проверок.
        /// </summary>
        /// <param name="processApiCommandName"></param>
        /// <returns></returns>
        public static bool IsChecksBypassCommand(string processApiCommandName)
        {
            var isCheckBypassCommand = string.Compare(processApiCommandName, "DiKaskoQuestionnaireStepCommand", StringComparison.OrdinalIgnoreCase) == 0 
                || string.Compare(processApiCommandName, nameof(Link2UploadFileInitCommand), StringComparison.OrdinalIgnoreCase) == 0
                || string.Compare(processApiCommandName, nameof(Link2GetPrintDocumentCommand), StringComparison.OrdinalIgnoreCase) == 0;

            return isCheckBypassCommand;
        }
    }
}


# Code\ExternalFunctions\DiKaskoAbTestTariffCalculation.cs
﻿using iRIS.Framework.Entity.Dictionary.ABTests;
using iRIS.Framework.Statement.Engine;
using System;
using Microsoft.Extensions.DependencyInjection;
using iRIS.InsuranceCore.Entities;
using iRIS.KaskoLink2.Code.Helpers;

namespace iRIS.KaskoLink2.Code.ExternalFunctions
{
    public class DiKaskoAbTestTariffCalculation : IExternalFunctionsInvoker
    {
        private const string ProcessName = "dikaskoinsurance";

        private readonly IABTestsManager _abTestsMnager;
        private readonly DiAbTestHelper _diAbTestHelper;

        public DiKaskoAbTestTariffCalculation(IServiceProvider serviceProvider)
        {
            _abTestsMnager = serviceProvider.GetRequiredService<IABTestsManager>();
            _diAbTestHelper = new DiAbTestHelper(_abTestsMnager);
        }

        public bool IsIrisCalculation(Basket basket)
        {
            _abTestsMnager.InitializeProcessTest("kaskoCalculation", ProcessName, basket.Number);
            return _diAbTestHelper.IsIrisCalculation();
        }

        public bool IsIrisCalculation()
        {
            return _diAbTestHelper.IsIrisCalculation();
        }
    }
}


# Code\ExternalFunctions\DiKaskoConstructorExternalFunctionsInvoker.cs
﻿using System;
using System.Collections.Generic;
using System.Linq;
using iRIS.Framework.RequestPipeline.Extensions;
using iRIS.Framework.Statement.Engine;
using iRIS.InsuranceCore.Code.ConstructorCore.Models;
using iRIS.InsuranceCore.Code.Extensions.Helpers;
using iRIS.InsuranceCore.Code.Interfaces.ConstructorCore;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Entities.EntityExtensions;
using iRIS.KaskoCore.Code.Constants;
using iRIS.KaskoLink2.Code.Constants;
using iRIS.KaskoLink2.Code.Constructor.Helpers.EntityExtensions;
using iRIS.KaskoLink2.Code.Interfaces;
using iRIS.KaskoLink2.Code.Interfaces.BankSettings;
using iRIS.KaskoLink2.Code.Link2;
using iRIS.KaskoLink2.Code.TypeExtensions;
using iRIS.KaskoLink2.ViewModels;
using Microsoft.Extensions.DependencyInjection;

namespace iRIS.KaskoLink2.Code.ExternalFunctions
{
    public class DiKaskoConstructorExternalFunctionsInvoker : IExternalFunctionsInvoker
    {
        private readonly IServiceProvider _serviceProvider;
        private readonly PipelineExecutionContext _context;

        public DiKaskoConstructorExternalFunctionsInvoker(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
            _context = _serviceProvider.GetService<PipelineExecutionContext>();
        }

        // Обрезать сумму риска, если сумма выходит за границы [sumMin, sumMax]
        public bool TruncateRiskSum(Deal deal, int structId, int sumMin, int sumMax)
        {
            if (HandleChangeItem(out var changedItem) &&
                changedItem.IsChecked && structId == changedItem.StructIds[0])
            {
                var dealHelper = new DealHelper(deal);
                var risk = dealHelper.DealRisks.FirstOrDefault(x => x.StructId == structId);

                if (risk?.Sum == null)
                {
                    return false;
                }

                if (risk.Sum < sumMin)
                {
                    risk.Sum = sumMin;
                }
                else if (risk.Sum > sumMax)
                {
                    risk.Sum = sumMax;
                }
            }

            return false;
        }

        public bool CheckAndSetInsuranceSum(Deal deal, int sumMax)
        {
            if (_context.ProcessSharedVariables.ContainsKey(DiKaskoLink2Constants.IsShortKaskoSelected)
                && _context.ProcessSharedVariables[DiKaskoLink2Constants.IsShortKaskoSelected] as string == bool.TrueString)
            {
                var dealHelper = new DealHelper(deal);
                var insuranceObject = dealHelper.InsuranceObjects.FirstOrDefault();

                if (insuranceObject?.InsuranceSumm != null)
                {
                    if (insuranceObject.InsuranceSumm > sumMax)
                    {
                        insuranceObject.InsuranceSumm = sumMax;
                    }
                }
            }

            return false;
        }

        // Возвращает сумму франшизы
        public decimal? GetFranchiseSum(Deal deal, int structId)
        {
            var dealHelper = new DealHelper(deal);
            var franchise = dealHelper.DealFranchises.FirstOrDefault(x => x.StructId == structId);

            return franchise?.Sum;
        }

        /// <summary>
        /// Функция определения необходимости проверки андеррайтинга.
        /// </summary>
        /// <param name="basket">Корзина.</param>
        /// <returns>Возвращает true, если требуется проверка андеррайтера, иначе false.</returns>
        public bool IsDiUnderwriterCheckRequired(Basket basket)
        {
            if (basket.IsClearOsago())
            {
                return false;
            }

            var kasko = basket.GetKaskoDeal();
            if (kasko == null)
            {
                return false;
            }

            return kasko.AutoDeal.DIUnderwriterApprovals
                .Any(ua => ua.StatusCode == DiUnderwriterApprovalStatusCodes.Required || string.IsNullOrEmpty(ua.StatusCode));
        }

        // Выбрано ли условие structId в дереве
        public bool IsConditionChecked(Deal deal, int structId)
        {
            var dealHelper = new DealHelper(deal);
            return dealHelper.DealOptions.Select(x => x.StructId).Contains(structId);
        }

        public bool IsDealInStatus(Deal deal, string statusCode)
        {
            if (deal == null)
            {
                throw new ArgumentNullException(nameof(deal));
            }

            if (string.IsNullOrWhiteSpace(statusCode))
            {
                throw new ArgumentNullException(nameof(statusCode));
            }

            return deal.DealStatusCode.Equals(statusCode, StringComparison.OrdinalIgnoreCase);
        }

        public bool IsConditionUnchecked(Deal deal, int structId)
        {
            return !IsConditionChecked(deal, structId);
        }

        // Проверка Check по условию changedStructId1 или changedStructId2 во вьюмодели
        public bool IsToggledConditionChecked(int changedStructId1, int changedStructId2)
        {
            var structIdsGroup = new List<int> { changedStructId1, changedStructId2 };

            return HandleChangeItem(out var changedItem) &&
                   changedItem.IsChecked && structIdsGroup.Contains(changedItem.StructIds[0]);
        }

        // Проверка Uncheck по условию changedStructId1 или changedStructId2 во вьюмодели
        public bool IsToggledConditionUnchecked(int changedStructId1, int changedStructId2)
        {
            var structIdsGroup = new List<int> { changedStructId1, changedStructId2 };

            return HandleChangeItem(out var changedItem) &&
                   !changedItem.IsChecked && structIdsGroup.Contains(changedItem.StructIds[0]);
        }

        // Проверка Check по changedStructId во вьюмодели
        public bool IsToggledConditionChecked(int changedStructId)
        {
            return HandleChangeItem(out var changedItem) &&
                   changedItem.IsChecked && changedItem.StructIds.Contains(changedStructId);
        }

        // Проверка Uncheck по changedStructId во вьюмодели
        public bool IsToggledConditionUnchecked(int changedStructId)
        {
            return HandleChangeItem(out var changedItem) &&
                   !changedItem.IsChecked && changedItem.StructIds.Contains(changedStructId);
        }

        public bool IsDamegeAndTotalDamege(Deal deal)
        {
            return new List<int> { StructIdsCodes.Damage, StructIdsCodes.TotalLoss }.All(x => new DealHelper(deal).DealRisks.Exists(risk => risk.StructId == x));
        }

        public bool IsOnlyTotalDamege(Deal deal)
        {
            var dealHelper = new DealHelper(deal);
            return dealHelper.DealRisks.Exists(x => x.StructId == StructIdsCodes.TotalLoss) &&
                   !dealHelper.DealRisks.Exists(x => x.StructId == StructIdsCodes.Damage);
        }

        public bool IsInstallmentCheckedRule(Deal deal)
        {
             return !_context.IsProcessApiRequest && (deal.CheckInstallmentRule() && deal.CheckInstallmentDamageRule());
        }

        public bool IsInstallmentUncheckedRule(Deal deal)
        {
            return !_context.IsProcessApiRequest && !(deal.CheckInstallmentRule() && deal.CheckInstallmentDamageRule());
        }

        public bool DagoUnAvailable(Deal deal)
        {
            var dagoAvailabilityChecker = _serviceProvider.GetRequiredService<IDagoAvailabilityChecker>();
            return !dagoAvailabilityChecker.DagoIsAvailable(deal);
        }

        // Выбран ли банк, не поддерживаемый франшизу по угону
        public bool HasBankWithoutKeysDocLossFranchise(Deal deal)
        {
            var febrary_03_2022 = new DateTime(2022, 2, 3, 16, 0, 0);
            if (deal.DateFirstCalculation < febrary_03_2022)
            {
                return false;
            }

            var bank = deal.SuggestedBanks.LastOrDefault();

            var bankList = new[] { "044525976", "044525823", "044525225", "044525630", "044525161" };

            return bank?.BIK != null && bankList.Contains(bank.BIK);
        }

        // Выбрана опция "Угон + Полная гибель" во вьюмодели
        public bool IsCarjackingAndTotalCheckedInViewModel()
        {
            var checkedInViewModel = HandleChangeItem(out var changedItem) && changedItem.IsChecked &&
                                     changedItem.StructIds.Count == 2 &&
                                     changedItem.StructIds.Contains(StructIdsCodes.CarjackingCode) &&
                                     changedItem.StructIds.Contains(StructIdsCodes.TotalLoss);

            return checkedInViewModel;
        }

        // Выбрана опция "Угон" во вьюмодели
        public bool IsCarjackingCheckedInViewModel()
        {
            var checkedInViewModel = HandleChangeItem(out var changedItem) && changedItem.IsChecked &&
                                     changedItem.StructIds.Count == 1 &&
                                     changedItem.StructIds[0] == StructIdsCodes.CarjackingCode;

            return checkedInViewModel;
        }

        // Выбрана опция "Угон" в сделке
        public bool IsCarjackingCheckedInDeal(Deal deal)
        {
            return deal.HasCarjackingOnly();
        }

        // Возможность выбора чистого Угона для партнерских котировок (FirstInitialization + UserInitialization)
        public bool EnableCarjackingForLink2(Deal deal, List<string> userGroups)
        {
            var link2ConstructorProposal = deal.Proposals.FirstOrDefault(x => x.Offer_Id == DiKaskoOfferIds.Link2Constructor);
// Идем непосредственно к блоку определения выхода из подпроцесса только если выполняется одно из условий:
            // нет ни ПСО, ни ОТА
            // есть завершенная ОТА
            if ((inspection == null && !IsOtaStepAdded(basket)) || (IsOtaStepAdded(basket) && !CanEditOtaStatus(basket)))
            {
                return false;
            }

            // если не выполнено любое из указанных выше условий, переходим к форме ожидания ОТА
            return true;
        }

        /// <summary>
        /// Проверка необходимости проведения проверки ОТА (подпроцесс ОТА для линковых партнеров и подпроцесс возобновления).
        /// </summary>
        public bool CanEditOtaStatus(Basket basket)
        {
            if (basket.GetKaskoDeal().AutoDeal.TryGetLastOtaApproval(out var approval))
            {
                return OtaHelper.Link2PartnersAccessStatuses.Contains(approval.OtaApprovalStatusCode);
            }

            return false;
        }

        /// <summary>
        /// Проверка возможности перехода в подпроцесс ОТА/ПСО в зависимости от статуса otaApproval (подпроцесс возобновления).
        /// </summary>
        public bool IsOtaStepAccessible(Basket basket)
        {
            if (basket.GetKaskoDeal().AutoDeal.TryGetLastOtaApproval(out var approval))
            {
                return OtaHelper.DocReviewerAccessStatusCodes.Contains(approval.OtaApprovalStatusCode);
            }

            return false;
        }

        public bool IsOtaFinalStep(Basket basket)
        {
            if (basket.GetKaskoDeal().AutoDeal.TryGetLastOtaApproval(out var approval))
            {
                return OtaHelper.OtaFinalStatuses.Contains(approval.OtaApprovalStatusCode);
            }

            return false;
        }

        /// <summary>
        /// Проверка возможности перехода в подпроцесс ОТА/ПСО зависимости от inspection (подпроцесс возобновления).
        /// </summary>
        public bool IsPsoStepAccessible(Basket basket)
        {
            var deal = basket.GetKaskoDeal();
            var inspection = _mediator.ResolveQuery<IQueryKaskoInspection>().GetInspectionByDealEntityId(deal.EntityId);

            return inspection != null;
        }

        public bool IsPaymentByA7Receipt(Basket basket)
        {
            return basket.GetKaskoDeal().Invoices.Any(i => i.PaymentTypeCode == PaymentTypeCodes.ByReceiptA7);
        }

        public void ProcessBamIntegrationLog(Basket basket, string errorMessage)
        {
            if (string.IsNullOrEmpty(errorMessage))
            {
                return;
            }

            basket.GetKaskoDeal().AutoDeal.BamIntegrationLog.Add(new BamIntegrationLog { ErrorMessage = errorMessage.TrimMaxLength(100) });
        }

        public void ProcessBamIntegrationResult(Basket basket, string a7number)
        {
            if (string.IsNullOrEmpty(a7number))
            {
                return;
            }

            foreach (var invoice in basket.GetKaskoDeal().Invoices)
            {
                invoice.A7Number = a7number;
            }
        }

        public bool CheckIsA7Number(Basket basket)
        {
            foreach (var invoice in basket.GetKaskoDeal().Invoices)
            {
                if (invoice.A7Number == null)
                {
                    return false;
                }
            }

            return true;
        }

        public string GetBasketRepaymentDate(Basket basket)
        {
            return basket.Payments.First().GetLetterRepaymentDate();
        }

        public void SetAutoCost(Basket basket)
        {
            var deal = basket.GetKaskoDeal();
            var autoCostCalculator = _serviceProvider.GetRequiredService<IAutoCostCalculator>();
            deal.GetAuto().AutoCost = autoCostCalculator.GetAutoCostAsync(deal).ConfigureAwait(false).GetAwaiter().GetResult();
        }

        /// <summary>
        /// Если в запросе на расчет передано имя оффера, помечает выбранный Proposal как IsSelected.
        /// Повторный прерасчет сделки на данном этапе не проводится, так как произойдет на сегментации.
        /// </summary>
        /// <param name="basket">корзина.</param>
        /// <param name="selectedPacketName">имя выбранного пакета.</param>
        public void SetSelectedProposal(Basket basket, string selectedPacketName)
        {
            if (string.IsNullOrEmpty(selectedPacketName))
            {
                return;
            }

            var deal = basket.GetKaskoDeal();

            var requestedProposal = deal.Proposals
                .FirstOrDefault(p => p.Offer.Name == selectedPacketName
                || p.Offer.OfferMappings.Any(om => om.PackageName == selectedPacketName));

            if (requestedProposal != null)
            {
                deal.SetSelectedProposal(requestedProposal);
            }
        }

        /// <summary>
        /// Возвращает признак выбранного оффера коробки.
        /// </summary>
        /// <param name="basket"></param>
        /// <returns>true, если выбранное предложение является оффером-коробкой.</returns>
        public bool IsBoxProposalSelected(Basket basket)
        {
            return basket.GetKaskoDeal()?.IsBox() == true;
        }

        public string GetOtaApprovalStatusCode(Basket basket)
        {
            if (basket.GetKaskoDeal().AutoDeal.TryGetLastOtaApproval(out var approval))
            {
                return approval.OtaApprovalStatusCode;
            }

            return null;
        }

        public string AlertMessageDocumentsNotAttached(Basket basket)
        {
            if (basket.EntityContext.TryGetValue(nameof(PreInsuranceCheckModel), out PreInsuranceCheckModel model)
                && !string.IsNullOrEmpty(model.Comment))
            {
                if (model.Type == PreInsuranceCheckTypes.Ota)
                {
                    return string.Empty;
                }

                return model.Comment;
            }

            return "Документы не приложены";
        }

        /// <summary>
        /// Включена ли настройка NeedSendMailBeforePaymentSetting.
        /// </summary>
        /// <param name="integrationLogin"></param>
        /// <returns></returns>
        public bool CanUseNeedSendMailBeforePaymentSetting(string integrationLogin)
        {
            return _entitySettingsManager.GetSettingForDefaultOrPartnerConfiguration(
                KaskoOsagoEntitySettingCodes.NeedSendMailBeforePaymentSetting,
                KaskoOsagoEntitySettingCodes.NeedSendMailBeforePaymentSettingDefault,
                KaskoOsagoEntitySettingCodes.NeedSendMailBeforePaymentSettingByIntegrationLogin,
                new IntegrationLogin { IntegrationLoginName = integrationLogin },
                true,
                _logger);
        }

        private Discount GetUrmDiscount(Basket basket) =>
            basket.GetKaskoDeal().GetSelectedDiscountCombination().Discounts.SingleOrDefault(d =>
                d.CalculationComponentCoefficient.Coefficient.Name.Equals(DiscountCoefficientNames.K_URM, StringComparison.OrdinalIgnoreCase));

        /// <summary>
        /// Проверка на факт наличия проверки ОТА.
        /// </summary>
        private bool IsOtaStepAdded(Basket basket)
        {
            return basket.GetKaskoDeal().AutoDeal.TryGetLastOtaApproval(out _);
        }

        /// <summary>
        /// Возвращает список кодов печатных форм, отправляемых после оплаты.
        /// </summary>
        /// <returns>Список кодов печатных форм.</returns>
        public string GetAfterPaymentPrintingFormCodes() => $"" +
            $"{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_LINK2_POLICY_AUTO_KASKO}," +
            $"{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_POLICY_KASKO_FALLING_OBJECT}," +
            $"{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_POLICY_KASKO_DISASTER}," +
            $"{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_POLICY_KASKO_DISASTER_AND_FALLING_OBJECT}," +
            $"{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_EKASKO_TERMS}," +
            $"{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_LINK2_KASKO_KID}," +
            $"{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_KASKO_KID_NO_POLICY}," +
            $"{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_POLICY_AUTO_DAGO}," +
            $"{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_POLICY_AUTO_KASKO_KID150}";

        /// <summary>
        /// Возвращает список кодов печатных форм, отправляемых перед оплатой.
        /// </summary>
        /// <param name="basket">Корзина.</param>
        /// <returns>Список кодов печатных форм.</returns>
        public string GetPrePaymentPrintingFormCodes(Basket basket)
        {
            var deal = basket.GetKaskoDeal();
            var printingFormCode = GetAfterPaymentPrintingFormCodes();

            printingFormCode += deal.Invoices.Any(i => i.PaymentTypeCode == PaymentTypeCodes.PaymentInvoice)
                ? $",{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_INVOICE_AUTO_KASKO}"
                : deal.Invoices.Any(i => i.PaymentTypeCode == PaymentTypeCodes.ByReceiptSber)
                    ? $",{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_RECEIPT_SBER_AUTO_KASKO}"
                    : deal.Invoices.Any(i => i.PaymentTypeCode == PaymentTypeCodes.ByReceiptA7)
                        ? $",{KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_RECEIPT_A7_AUTO_KASKO}"
                        : string.Empty;

            return printingFormCode;
        }

        public bool NeedGeneratePaymentLink(Basket basket)
        {
            if (basket == null)
            {
                return false;
            }

            if (!basket.Payments.Any() || string.IsNullOrEmpty(basket.Payments[0].Hash))
            {
                return true;
            }

            return false;
        }

        public void SavePaymentLink(Basket basket, string paymentLink)
        {
            if (!string.IsNullOrEmpty(paymentLink))
            {
                basket.SetPaymentLink(paymentLink);
            }
        }

        public void SaveDateRepayment(Basket basket, string dateRepayment)
        {
            if (!string.IsNullOrEmpty(dateRepayment))
            {
                basket.SetDateRepayment(dateRepayment);
            }
        }

        /// <summary>
        /// Проверка признака партнера B2C.
        /// </summary>
        /// <returns>Результат проверки.</returns>
        public bool IsB2CPartner(string integrationLogin)
        {
            var isB2CPartner = CheckIsB2CPartnerHelper.CheckIsB2CPartner(_entitySettingsManager, integrationLogin);

            return isB2CPartner;
        }

        /// <summary>
        /// Функция для проверки, есть ли ручные заявки на проверку андеррайтера.
        /// </summary>
        /// <param name="basket">Текущая корзина со сделками.</param>
        /// <returns>Возвращает true, если нет ручных заявок или они со статусами Accepted.</returns>
        public bool HasDIUnderwriterIsSystemCreatedApproval(Basket basket)
        {
            var nonSystemCreatedApprovals = basket.GetKaskoDeal().AutoDeal.DIUnderwriterApprovals?.Where(ua => ua.IsSystemCreated == false);

            if (nonSystemCreatedApprovals?.Any() != true)
            {
                return true;
            }

            return nonSystemCreatedApprovals.All(ua =>
                DiUnderwriterApprovalStatusCodes.AcceptedStatuses.Contains(ua.StatusCode)
                || (ua.ThemeCode == DIUnderwriterApprovalThemeCodes.Link2PersDiscount && ua.StatusCode == DiUnderwriterApprovalStatusCodes.Rejected));
        }

        public bool HasManualUnderwriterApprovals(Basket basket)
        {
            var autoDeal = basket.GetKaskoDeal().AutoDeal;
            var diUnderwriterApprovals = autoDeal.DIUnderwriterApprovals;
            return diUnderwriterApprovals.Any(x => x.IsSystemCreated == false);
        }

        public bool IsAutoCostInAcceptedLimits(Basket basket)
        {
            var deal = basket.GetKaskoDeal();
            var auto = deal.GetAuto();
            var autoCost = auto.AutoCost;

            var isAutoCostInLimits = deal.AutoDeal.DIUnderwriterApprovals
                .Where(x => 
                    x.AutoCostApproval.HasValue
                    && DiUnderwriterApprovalStatusCodes.AcceptedStatuses.Contains(x.StatusCode)
                    && DIUnderwriterApprovalThemeCodes.Link2ThemesToCheckAutoCost.Contains(x.ThemeCode))
                .GroupBy(x => x.ThemeCode)
                .Select(g => g.OrderByDescending(z => z.CreateDate).FirstOrDefault())
                .All(x => IsValid(autoCost, x.AutoCostApproval, x.ThemeCode, deal.IsProlongation));

            return isAutoCostInLimits;

            bool IsValid(decimal? autocost, decimal? acceptedLimit, string themeCode, bool? isProlongation) => themeCode switch
            {
                (DIUnderwriterApprovalThemeCodes.VehCostOver15000000ForLink2 or
                DIUnderwriterApprovalThemeCodes.VehCostOver5000000ForLink2 or
                DIUnderwriterApprovalThemeCodes.VehCostOver7000000ForLink2) when
                    isProlongation != true && autocost <= acceptedLimit => true,

                DIUnderwriterApprovalThemeCodes.VehCostIsAboveRangeForLink2 when
                    autocost <= acceptedLimit => true,

                DIUnderwriterApprovalThemeCodes.VehCostOver10000000ForProlongationLink2 when
                    isProlongation == true && autocost <= acceptedLimit => true,

                DIUnderwriterApprovalThemeCodes.VehCostIsBelowRangeForLink2 when
                    isProlongation == true && autocost >= acceptedLimit => true,

                _ => false,
            };
        }

        public bool IsAutoCostInAcceptedLimits()
        {
            var basket = _context.GetBasket();
            return IsAutoCostInAcceptedLimits(basket);
        }

        /// <summary>
        /// Проверка признака апсейла.
        /// </summary>
        /// <param name="basket">Корзина.</param>
        /// <returns>bool.</returns>
        public bool CheckIsUpsale(Basket basket)
        {
            var isUpsale = basket.IsUpsale();

            _logger
                .ForContext<DiKaskoExternalFunctionsInvoker>()
                .ForContext("ProcessKey", basket.Number)
                .Information($"Проверка признака апсейла: {isUpsale}.");

            return isUpsale;
        }

        public bool HasUrmApprovals(Basket basket)
        {
            if (basket.GetKaskoDeal().AutoDeal.TryGetLastUrmApproval(out var approval))
            {
                if (approval?.URMApprovalStatusCode != null)
                {
                    return true;
                }
            }

            return false;
        }

        public bool HasChecksInWork(Basket basket)
        {
            if (basket.EntityContext.TryGetValue(nameof(PreInsuranceCheckModel), out PreInsuranceCheckModel model) && model != null)
            {
                return model.Status != UrmApprovalStatusCodes.Accepted;
            }

            var deal = basket.GetKaskoDeal();
            var sasIsRejected = deal.AutoDeal.SASApproval.Any(x => x.SASApprovalStatusCode == SasApprovalStatusCodes.Rejected);

            return deal.DealStatus.Code == "InWork" && !sasIsRejected;
        }

        public Basket DeepCopyBasket(Basket inputBasket)
        {
            if (inputBasket == null)
            {
                return null;
            }

            var basket = inputBasket.DeepCopy();
            basket.Id = 0;
            basket.EntityId = 0;

            return basket;
        }
    }
}

# Code\ExternalFunctions\DiKaskoProlongationTestModeChecker.cs
﻿using System;

using iRIS.Framework.Entity.Dictionary.EntitySettings;
using iRIS.Framework.Statement.Engine;
using iRIS.InsuranceCore;
using iRIS.KaskoLink2.Code.Helpers;

using Microsoft.Extensions.Options;

namespace iRIS.KaskoLink2.Code.ExternalFunctions
{
    [Obsolete]
    public class DiKaskoProlongationTestModeChecker : IExternalFunctionsInvoker
    {
        private readonly IEntitySettingsManager _entitySettingsManager;
        private readonly IOptions<InsuranceCoreModuleConfiguration> _insuranceCoreConfiguration;
какой параметр в запросе отвечает за перерасчет корзины?