You are a helpful assistant.
using iRIS.Framework.Configuration;
using iRIS.Framework.Cqrs.Interfaces;
using iRIS.Framework.Data;
using iRIS.Framework.Data.Services.Client;
using iRIS.Framework.Entity.Metadata.Manager.Interfaces;
using iRIS.Framework.ExtensionMethods;
using iRIS.Framework.FileManagement;
using iRIS.Framework.Link2;
using iRIS.Framework.Link2.AppServices;
using iRIS.Framework.Link2.Contract;
using iRIS.Framework.Link2.Extensions;
using iRIS.Framework.Link2.Generated.ViewModels;
using iRIS.Framework.Link2.Metadata;
using iRIS.Framework.RequestPipeline.Extensions;
using iRIS.Framework.RequestPipeline.Pipelines;
using iRIS.Framework.Security.Entities;
using iRIS.Framework.UI.PresentationModel;
using iRIS.Framework.Validation;
using iRIS.InsuranceCore;
using iRIS.InsuranceCore.Code.CustomProcesses.BasketPreparationProcess.Enums;
using iRIS.InsuranceCore.Code.Implementations;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Entities.EntityExtensions;
using iRIS.InsuranceCore.Entities.Enums;
using iRIS.InsuranceCore.Infrastructure.Extensions;
using iRIS.KaskoCore.Code.Constants;
using iRIS.KaskoCore.Code.Helpers;
using iRIS.KaskoCore.Siebel.Code.Helpers;
using iRIS.KaskoLink2.Code.Constants;
using iRIS.KaskoLink2.Code.Helpers;
using iRIS.KaskoLink2.Code.Link2.PsoInspectionInfo;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Serilog;
using Serilog.Context;
using Siebel.Code.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using iRIS.Framework.Entity.Dictionary.EntitySettings;
using iRIS.KaskoCore.Code.Queries;
using iRIS.KaskoLink2.Code.EntityExtensions;

namespace iRIS.KaskoLink2.Code.Link2.ResponseCreation
{
    /// <summary>
    /// Создатель ответов Link2 для каско.
    /// </summary>
    public class DiKaskoCommonResponseCreator : KaskoCommonResponseCreator, IAsyncLink2StatusResponseCreator, IAsyncLink2ResponseCreator
    {
        private const string KaskoProductName = "КАСКО";
        private readonly string[] _innerSystemSourceCodes = new[] { "CS", "OA" };

        private readonly IOptions<InsuranceCoreModuleConfiguration> _settings;
        private readonly IQueryServiceInvoker _queryServiceInvoker;
        private readonly IPsoInspectionFileGroupsProvider _psoFileProvider;
        private readonly ILogger _logger;
        private readonly InsuranceCoreModuleConfiguration _coreConfiguration;
        private readonly IServiceProvider _serviceProvider;
        private readonly IEntitySettingsManager _entitySettingsManager;

        /// <summary>
        /// Initializes a new instance of the <see cref="DiKaskoCommonResponseCreator"/> class.
        /// </summary>
        /// <param name="queryServiceInvoker">Клиент сервиса запросов.</param>
        /// <param name="settings">Настройки модуля.</param>
        /// <param name="partnerSettingsService">Сервис настроек партнера.</param>
        /// <param name="serviceProvider">Сервис-провыайдер.</param>
        /// <param name="mediator">Медиатор запросов.</param>
        /// <param name="aggregator">Аггрегатор результатов валидации.</param>
        /// <param name="metadataManager">Менеджер метаданных.</param>
        /// <param name="processApiContext">Контекст Process API.</param>
        /// <param name="fileEntityFinder">Поисковик файлов.</param>        
        /// <param name="appConfiguration">Конфигурация приложения.</param>
        /// <param name="psoFileProvider">Провайдер файлов ПСО.</param>
        /// <param name="logger">Логгер.</param>
        /// <param name="coreConfiguration">Конфигурация ядра.</param>
        public DiKaskoCommonResponseCreator(
            IQueryServiceInvoker queryServiceInvoker,
            IOptions<InsuranceCoreModuleConfiguration> settings,
            IPartnerSettingsService partnerSettingsService,
            IServiceProvider serviceProvider,
            ICqrsMediator mediator,
            IValidationResultsAggregator aggregator,
            IMetadataManager metadataManager,
            ProcessApiContext processApiContext,
            IFileEntityFinder fileEntityFinder,
            IOptions<BusinessAppConfiguration> appConfiguration,
            IPsoInspectionFileGroupsProvider psoFileProvider,
            ILogger logger,
            IOptions<InsuranceCoreModuleConfiguration> coreConfiguration,
            IEntitySettingsManager entitySettingsManager)
            : base(partnerSettingsService, serviceProvider, mediator, aggregator, metadataManager, processApiContext, fileEntityFinder, appConfiguration, coreConfiguration)
        {
            _settings = settings;
            _serviceProvider = serviceProvider;
            _queryServiceInvoker = queryServiceInvoker;
            _psoFileProvider = psoFileProvider;
            _logger = logger;
            _entitySettingsManager = entitySettingsManager;
            _coreConfiguration = coreConfiguration.Value;
        }

        /// <inheritdoc/>
        public string ProcessName => "DiKaskoInsurance";

        public string CommandName => string.Empty;

        /// <inheritdoc/>
        public async Task<AccountStatusResponseDto<ModelStatusResponseDto>> CreateStatusResponseAsync(PipelineExecutionContext context, string commandName)
        {
            var response = await CreateResponseByContextAsync(context, commandName);

            if (CheckIsB2CPartner())
            {
                PopulateAvailablePaymentMethods(context, response);
                FillSiebelAccountStatus(context, response);
                FillPaymentLink(context, response);
                FillPsoFilesInformation(response, context);
                ReplacePrintingFormsCodes(response);
                SetDescriptionToFileGroups(response, context);
            }
            else
            {
                PopulateAvailablePaymentMethods(context, response);
                FillPaymentLink(context, response);
                SetDescriptionToFileGroups(response, context);
            }

            return new AccountStatusResponseDto<ModelStatusResponseDto>
            {
                Model = response.Model,
                Messages = response.Messages,
                AvailablePaymentMethods = response.AvailablePaymentMethods,
                OnlinePaymentUrl = response.OnlinePaymentUrl
            };
        }

        private void FillPaymentLink(PipelineExecutionContext context, ResponseDto<ModelResponseDto> response)
        {
            if (ProcessApiContext?.IsUpsale() == true)
            {
                return;
            }

            if (response.AvailablePaymentMethods.Any(x => x.Type == PaymentMethodType.Online))
            {
                var basket = context.GetBasket();
                if (basket != null && basket.TryGetPaymentLink(out var paymentLink) == true)
                {
                    response.OnlinePaymentUrl = paymentLink;
                }
                else
                {
                    var hash = basket.Payments?.FirstOrDefault()?.Hash;
                    if (hash != null)
                    {
                        response.OnlinePaymentUrl = $"{_coreConfiguration.UniversalOnlinePaymentUrl}di/process/UniversalOnlinePaymentProcess/new?UniversalOnlinePaymentDataHash={hash}";
                    }
                }
            }
        }

        /// <inheritdoc/>
        public override async Task<ResponseDto<ModelResponseDto>> CreateResponseAsync(PipelineExecutionContext context, string commandName)
        {
            var response = CheckIsB2CPartner()
                ? await CreateResponseAsyncDi(context, commandName)
                : await CreateResponseAsyncB2B(context, commandName);

            return response;
        }

        protected override async Task<ModelResponseDto> CreateModelAsync(PipelineExecutionContext context)
        {
            var model = await base.CreateModelAsync(context);

            foreach (var dealDto in model.Deals)
            {
                if (dealDto is DiKaskoResponseDealDto kaskoDealDto && kaskoDealDto.ProductName == KaskoProductName)
                {
                    kaskoDealDto.Price = model.Price;
                }
            }

            CleanAccountNumber(model);
            FillCrossKaskoInfo(model, context);

            var basket = context.GetBasket();
            if (basket != null)
            {
                SetInsuranceSum(model, basket.GetKaskoDeal());
            }

            return model;
        }

        /// <summary>
        /// Заполение InsuranceSum для пролонгации.
        /// </summary>
        /// <param name="model"></param>
        /// <param name="kaskoDeal"></param>
        private void SetInsuranceSum(ModelResponseDto model, Deal kaskoDeal)
        {
            if (kaskoDeal != null && model is DiKaskoModelResponseDto kaskoModel)
            {
                var insuranceObject = kaskoDeal.InsuranceObjects.FirstOrDefault();

                if (insuranceObject != null && insuranceObject.InsuranceSumm != null)
                {
                    kaskoModel.InsuranceSum = (decimal)insuranceObject.InsuranceSumm;
                }
            }
        }

        private void CleanAccountNumber(ModelResponseDto model)
        {
            if (string.IsNullOrEmpty(model.AccountNumber))
            {
                return;
            }

            if (!AccountNumberHelper.TryExtractBasketNumber(model.AccountNumber, out var basketNumber))
            {
                throw new Exception("Номер корзины невалиден");
            }

            model.AccountNumber = basketNumber;
        }

        private void FillCrossKaskoInfo(ModelResponseDto model, PipelineExecutionContext context)
        {
            if (context.ProcessSharedVariables.ContainsKey(Link2Constants.CrossSum) &&
                model is DiKaskoModelResponseDto kaskoModel)
            {
                const decimal kaskoCrossKv = 90;
                kaskoModel.Kv = kaskoCrossKv;
                kaskoModel.MainProductDiscount = model.Price;
                kaskoModel.DiscountDueToMainProductKv = true;
            }
        }

        /// <inheritdoc/>
        protected override ModelResponseDto CreateModelInstance() => new DiKaskoModelResponseDto();

        /// <inheritdoc/>
        protected override void FillMessages(ResponseDto<ModelResponseDto> response, PipelineExecutionContext context, string commandName)
        {
            if (CheckIsB2CPartner())
            {
                FillMessagesDi(response, context, commandName);
            }
            else
            {
                FillMessagesB2B(response, context, commandName);
            }
        }

        private void FillSiebelAccountStatus(PipelineExecutionContext context, ResponseDto<ModelResponseDto> response)
        {
            var basket = context.GetBasket();

            if (basket?.IsLead == true && SiebelAccountStatusHelper.SiebelAccountStatusRequired(context))
            {
                var logger = context.ServiceProvider.GetRequiredService<ILogger>();
                var siebelServiceInvoker = context.ServiceProvider.GetRequiredService<ISiebelServiceInvoker>();

                try
                {
                    var siebelResponse = siebelServiceInvoker.GetDenialReason(basket.Number);

                    if (siebelResponse.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(siebelResponse.DenialReason))
                    {
                        var deal = (DiKaskoResponseDealDto)response.Model.Deals.FirstOrDefault(d => d.ProductName == KaskoProductName);

                        deal.LeadStatus = siebelResponse.DenialReason;

                        logger.ForContext("BasketNumber", basket.Number).Information("Получение статуса котировки в Siebel: {DenialReason}", siebelResponse.DenialReason);
                    }
                    else if (!string.IsNullOrEmpty(siebelResponse.ErrorMessage))
                    {
                        logger.ForContext("BasketNumber", basket.Number).Error("Получение статуса котировки в Siebel: {ErrorMessage}", siebelResponse.ErrorMessage);
                    }
                }
                catch (Exception ex)
                {
                    logger.ForContext("BasketNumber", basket.Number).Warning(ex, "Возникла ошибка при получении статуса котировки в Siebel");

                    response.Messages.Add(new MessageResponseDto()
                    {
                        Level = ResponseMessageLevel.Warning,
                        Text = "Возникла ошибка при получении статуса котировки в Siebel"
                    });
                }
            }
        }

        /// <inheritdoc/>
        protected override DealStatusResponseDto GetDealInfo(DealStatusResponseDto dealDto, Deal deal, List<AvailablePacketDto> packets)
        {
            var response = CheckIsB2CPartner()
                ? GetDealInfoDi(dealDto, deal, packets)
                : GetDealInfoB2B(dealDto, deal, packets);

            return response;
        }

        private void FillPreviousPolicyConditions(DiKaskoResponseDealDto kaskoDealDto, Deal deal, List<AvailablePacketDto> packets)
        {
            if (ProcessApiContext.Command is DIKaskoCalculationLink2Command && deal.IsProlongation == true)
            {
                var coverages = packets?.FirstOrDefault(p => p.PackageName == "Каско")?.ObjectConditions?.SelectMany(oc => oc.Coverages);

                if (coverages != null)
                {
                    kaskoDealDto.PrevPolicyConditions = new PrevPolicyConditionsDto
                    {
                        Risks = coverages.SelectMany(c => c.Risks).Where(r => r.IsSelected).Select(r => r.Name).ToArray(),
                        Options = coverages.SelectMany(c => c.Options).Where(o => o.IsSelected).Select(o => o.Name)
                            .Concat(coverages.SelectMany(c => c.Risks).SelectMany(r => r.Options).Where(r => r.IsSelected).Select(r => r.Name)).ToArray(),
                        Franchises = coverages.SelectMany(c => c.Risks).SelectMany(r => r.Franchises)
                            .Where(f => f.IsSelected && f.PriceDeltas?.Where(pd => pd.IsSelected == true && pd.Value.HasValue).Count() > 0)
                                .Select(f => $"{f.Name}: {f.PriceDeltas?.FirstOrDefault(pd => pd.IsSelected).Value}").ToArray()
                    };
                }
            }
        }

        /// <summary>
        /// Заполняет статус проверки андеррайтинга.
        /// </summary>
        /// <param name="kaskoDealDto">Дто с данными сделки.</param>
        /// <param name="deal">Сделка.</param>
        protected void FillUnderwriterStatus(DiKaskoResponseDealDto kaskoDealDto, Deal deal)
        {
            if (deal?.AutoDeal?.DIUnderwriterApprovals == null || deal.AutoDeal.DIUnderwriterApprovals.Count < 1)
            {
                kaskoDealDto.UnderwriterApprovalStatus = DiUnderwriterApprovalStatusCodes.NotRequired;
                return;
            }

            var acceptedStatuses = KaskoOsagoHelper.GetUnderwriterApprovalLink2AcceptedStatuses();
            bool allApprovalsIsAccepted = deal.AutoDeal.DIUnderwriterApprovals.All(o => acceptedStatuses.Contains(o.StatusCode));
            if (allApprovalsIsAccepted)
            {
                kaskoDealDto.UnderwriterApprovalStatus = deal.AutoDeal.DIUnderwriterApprovals.All(x => x.IsClosed == true)
                    ? DiUnderwriterApprovalStatusCodes.Accepted
                    : DiUnderwriterApprovalStatusCodes.InWork;

                // возвращаем первый попавышийся коммент, т.к. нет логики для составления UnderwriterApprovalDescription из нескольких комментов
                kaskoDealDto.UnderwriterApprovalDescription = deal.AutoDeal.DIUnderwriterApprovals.Select(p => p.Commentary).Where(c => c != null).LastOrDefault();

                return;
            }

            if (SetStatusAndDescription(kaskoDealDto, deal, DiUnderwriterApprovalStatusCodes.Rejected) ||
            SetStatusAndDescription(kaskoDealDto, deal, DiUnderwriterApprovalStatusCodes.InWork) ||
            SetStatusAndDescription(kaskoDealDto, deal, DiUnderwriterApprovalStatusCodes.Required) ||
            SetStatusAndDescription(kaskoDealDto, deal, DiUnderwriterApprovalStatusCodes.RequiredExtraInfo) ||
            SetStatusAndDescription(kaskoDealDto, deal, DiUnderwriterApprovalStatusCodes.AcceptedWithLimits))
            {
                return;
            }

            kaskoDealDto.UnderwriterApprovalStatus = DiUnderwriterApprovalStatusCodes.Rejected;
        }

        private bool SetStatusAndDescription(DiKaskoResponseDealDto kaskoDealDto, Deal deal, string statusCode)
        {
            var last = deal.AutoDeal.DIUnderwriterApprovals.LastOrDefault(a => a.StatusCode.EqualsIgnoreCase(statusCode));
            if (last != null)
            {
                kaskoDealDto.UnderwriterApprovalStatus = statusCode;
                kaskoDealDto.UnderwriterApprovalDescription = last.Commentary;

                return true;
            }

            return false;
        }

        protected override async Task<List<AvailablePacketDto>> CreatePacketsInfoAsync(Deal deal, bool? useDrafts, bool needCreatePackets)
        {
            var hasKaskoPacketName = HasKaskoPacketName();
            needCreatePackets = needCreatePackets || hasKaskoPacketName;

            var packets = await base.CreatePacketsInfoAsync(deal, useDrafts, needCreatePackets);

            if (hasKaskoPacketName
                &&
                deal.Product.ProductDictCode == "KASKO"
                &&
                deal.DealStatusCode != EntityStatusType.OfferDefinition.ToString())
            {
                return packets?.Where(x => x.Name.ToUpper() == "КАСКО").ToList();
            }

            return packets;
        }

        protected override List<Offer> GetOffers(Deal deal, DateTime currentDate)
        {
            var offers = base.GetOffers(deal, currentDate);

            if (deal.IsProlongation == true)
            {
                return offers.Where(x => x.Id == DiKaskoOfferIds.Link2Constructor || x.IsConstructorOffer == true).ToList();
            }

            return offers;
        }

        /// <summary>
        /// Получение статуса проверки ПСО.
        /// </summary>
        /// <param name="dealEntityId">Id сделки.</param>
        /// <returns>Код статуса ПСО.</returns>
        private Inspection GetInspection(int dealEntityId)
        {
            var inspection = _queryServiceInvoker
                .GetByExpression<Inspection>(z => z.Where(x => x.DealEntityId == dealEntityId
                    && (x.State == VersionState.Current || x.State == VersionState.Draft)))
                .OrderByDescending(x => x.CreateDate)
                .FirstOrDefault();

            return inspection;
        }

        private void FillPsoFilesInformation(ResponseDto<ModelResponseDto> response, PipelineExecutionContext context)
        {
            var basket = context.Entities.ContainsKey("Basket") ? context.Entities["Basket"] as Basket : null;
            var deal = basket?.GetKaskoDeal();

            if (basket == null || deal == null)
            {
                return;
            }

            try
            {
                var psoInspectionInfoLoadResult = _psoFileProvider.LoadPsoInspectionFileGroups(basket, deal);
                switch (psoInspectionInfoLoadResult.ErrorType)
                {
                    case PsoInpectionFileGroupsLoadErrorTypes.None:
                        response.Model.FileGroups.AddRange(psoInspectionInfoLoadResult.FileGroups);
                        break;
                    default:
                        response.Messages.Add(new MessageResponseDto()
                        {
                            Level = ResponseMessageLevel.Warning,
                            Text = "Ошибка загрузки информации о необходимых файлах в процессе ПСО"
                        });
                        break;
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Ошибка загрузки информации о необходимых файлах в процессе ПСО");
                response.Messages.Add(new MessageResponseDto()
                {
                    Level = ResponseMessageLevel.Warning,
                    Text = "Ошибка загрузки информации о необходимых файлах в процессе ПСО"
                });
            }
        }

        private void ReplacePathMessages(ResponseDto<ModelResponseDto> response)
        {
            var suggestedBanksName = "Basket.Deals.SuggestedBanks.Name";

            foreach (var message in response.Messages)
            {
                if (string.IsNullOrEmpty(message.Path))
                {
                    continue;
                }

                if (message.Path == suggestedBanksName)
                {
                    message.Path = "bankOfCredit";
                }
            }
        }

        private bool HasKaskoPacketName()
        {
            if (ProcessApiContext?.ViewModel?.GetDictionary().ContainsKey("Deals") == true)
            {
                var dealViewModels = ProcessApiContext.ViewModel.GetListOfViewModel("Deals");
                if (dealViewModels != null && dealViewModels.Count > 0)
                {
                    var selectedPacket = dealViewModels[0]["Conditions"] as Link2SelectedPacketViewModel;
                    var packetName = selectedPacket != null
                                    ? selectedPacket["PacketName"] as string
                                    : string.Empty;

                    if (!string.IsNullOrEmpty(packetName) && packetName.ToUpper() == "КАСКО")
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// Фильтрация рисков для b2b процесса.
        /// </summary>
        /// <param name="offerProductConfigs"></param>
        /// <param name="parentStructId"></param>
        /// <returns>Все доступные риски.</returns>
        protected override List<Tuple<int?, ProductRisk>> GetProductRisksFiltered(List<ProductConfiguration> offerProductConfigs, int? parentStructId)
        {
            if (CheckIsB2CPartner())
            {
                return base.GetProductRisksFiltered(offerProductConfigs, parentStructId);
            }

            return offerProductConfigs
                .Where(x => x?.ProductConfigurationChildType.ChildTypeCode == "Risk")
                .Where(x => x.ProductRisk != null)
                .Where(x => x.IsDeleted != true)
                .Where(x => x.ParentStructId == parentStructId)
                .Select(x => new Tuple<int?, ProductRisk>(x.StructId, x.ProductRisk))
                .ToList();
        }

        /// <summary>
        /// Простановка понятного описания файловым группам.
        /// </summary>
        private void SetDescriptionToFileGroups(ResponseDto<ModelResponseDto> response, PipelineExecutionContext context)
        {
            SetDescription(
                "damagepsodocs",
                "[2 ФОТО ПОВРЕЖДЕНИЯ] Сделайте фотографию повреждения автомобиля. Для каждого повреждения требуется 2 фотографии: 1-я - фото детали, на которой имеется повреждение (расстояние 1 - 1,5 м), вместе с сопряженными деталями; 2-я - крупный план самого повреждения (расстояние 0,3 м)",
                "Повреждения");

            SetDescription(
                "traditionalpsodocs",
                "Сделайте 14 фотографий автомобиля (Место осмотра; VIN; Передняя часть ТС; Передняя часть ТС – правый бок; Правая сторона ТС; Задняя часть ТС – правый бок; Задняя часть ТС; Задняя часть ТС – левый бок; Левая сторона ТС; Передняя часть ТС – левый бок; Лобовое стекло; Колесо; Передний ряд сидений; Приборная панель, показания одометра).",
                "Фотографии осмотра для ПСО");

            SetDescription(
                "optequipmentpsodocs",
                "Сделайте фотографию каждой позиции дополнительного оборудования, которое принимается на страхование",
                "Дополнительное оборудование");

            void SetDescription(string fileGroupName, string description, string newFileGroupName)
            {
                var fileGroup = response.Model.FileGroups.FirstOrDefault(f => f.FileGroup?.ToLower() == fileGroupName);
                if (fileGroup != null)
                {
                    fileGroup.Description = description;
                    fileGroup.FileGroup = newFileGroupName;
                }
            }
        }

        /// <summary>
        /// Простановка доступного КВ для внутренних пользователей - CS и OA.
        /// </summary>
        private void SetAvailableCommissionValue(DiKaskoResponseDealDto kaskoDealDto, Deal deal)
        {
            if (ProcessApiContext.Command is DIKaskoCalculationLink2Command && ProcessApiContext.InputParameters.ContainsKey(Link2Constants.IntegrationLoginKey))
            {
                var login = ProcessApiContext.InputParameters[Link2Constants.IntegrationLoginKey];
                var integrationLoginEntity = _queryServiceInvoker
                    .GetByExpression<IntegrationLogin>(x => x.Where(u => u.IntegrationLoginName.Equals(login, StringComparison.OrdinalIgnoreCase)))
                    .SingleOrDefault();

                if (integrationLoginEntity != null && _innerSystemSourceCodes.Contains(integrationLoginEntity.SystemSourceCode))
                {
                    kaskoDealDto.AvailableCommissionDiscount = deal.DealIntermediaries.SingleOrDefault(di => di.IsMain == true)?.CommisionValue;
                }
            }
        }

        /// <summary>
        /// Простановка значения коэффициента УРМ.
        /// </summary>
        private void SetUrmCoefficient(DiKaskoResponseDealDto kaskoDealDto, Deal deal)
        {
            if (ProcessApiContext.IsUpsale() == true)
            {
                return;
            }

            if (ProcessApiContext.Command is Link2GetStatusCommand || ProcessApiContext.Command is DIKaskoContinueProcessLink2Command)
            {
                kaskoDealDto.UrmCoefficient = deal.GetSelectedDiscountCombination().Discounts.SingleOrDefault(d =>
                    d.CalculationComponentCoefficient.Coefficient.Name.Equals(DiscountCoefficientNames.K_URM, StringComparison.OrdinalIgnoreCase))?.DiscountValue;
            }
        }

        private void FillPreviousPolicyConditionsB2B(DiKaskoResponseDealDto kaskoDealDto, Deal deal, List<AvailablePacketDto> packets)
        {
            // спросить
            if (ProcessApiContext.Command is DIKaskoCalculationLink2Command && deal.IsProlongation == true)
            {
                var coverages = packets?.FirstOrDefault(p => p.PackageName == OfferNames.ProlongationConstructorName)?.ObjectConditions?.SelectMany(oc => oc.Coverages);

                if (coverages != null)
                {
                    kaskoDealDto.PrevPolicyConditions = new PrevPolicyConditionsDto
                    {
                        Risks = coverages.SelectMany(c => c.Risks).Where(r => r.IsSelected).Select(r => r.Name).ToArray(),
                        Options = coverages.SelectMany(c => c.Options).Where(o => o.IsSelected).Select(o => o.Name)
                            .Concat(coverages.SelectMany(c => c.Risks).SelectMany(r => r.Options).Where(r => r.IsSelected).Select(r => r.Name)).ToArray(),
                        Franchises = coverages.SelectMany(c => c.Risks).SelectMany(r => r.Franchises)
                            .Where(f => f.IsSelected && f.PriceDeltas?.Where(pd => pd.IsSelected == true && pd.Value.HasValue).Count() > 0)
                                .Select(f => $"{f.Name}: {f.PriceDeltas?.FirstOrDefault(pd => pd.IsSelected).Value}").ToArray()
                    };
                }
            }
        }

        private bool CheckIsB2CPartner()
        {
            var processApiContext = _serviceProvider.GetRequiredService<ProcessApiContext>();
            var integrationLogin = processApiContext.IntegrationLogin();

            return CheckIsB2CPartnerHelper.CheckIsB2CPartner(_entitySettingsManager, integrationLogin);
        }

        private async Task<ResponseDto<ModelResponseDto>> CreateResponseAsyncDi(PipelineExecutionContext context, string commandName)
        {
            var basket = context.GetBasket();

            if (basket?.Number != null)
            {
                LogContext.PushProperty("ProcessKey", basket.Number);
            }

            var response = await base.CreateResponseAsync(context, commandName);

            FillPsoFilesInformation(response, context);
            ReplacePathMessages(response);
            SetDescriptionToFileGroups(response, context);

            UnloadUnsuccessfulProcess(response, context);

            return response;
        }

        private async Task<ResponseDto<ModelResponseDto>> CreateResponseAsyncB2B(PipelineExecutionContext context, string commandName)
        {
            var response = await base.CreateResponseAsync(context, commandName);

            SetDescriptionToFileGroups(response, context);
            UnloadUnsuccessfulProcess(response, context);
            FillPaymentLink(context, response);

            return response;
        }

        private DealStatusResponseDto GetDealInfoDi(DealStatusResponseDto dealDto, Deal deal, List<AvailablePacketDto> packets)
        {
            dealDto = base.GetDealInfo(dealDto, deal, packets);

            if (dealDto is DiKaskoResponseDealDto kaskoDealDto
                && deal.Product.ProductDictCode == "KASKO")
            {
                kaskoDealDto.PsoLinks = new PsoLinksResponseDto
                {
                    Android = _settings?.Value?.AndroidViewAppMobileClientInstallUrl,
                    IOs = _settings?.Value?.IOsViewAppMobileClientInstallUrl,
                };

                var inspection = GetInspection(deal.EntityId);
                if (inspection != null)
                {
                    kaskoDealDto.PsoStatus = inspection.InspectionStatusCode;
                    kaskoDealDto.PsoStatusDescription = inspection.StatusChangeDescription;
                    kaskoDealDto.PostponedPso = inspection.PostponedInspection;
                }

                if (deal.AutoDeal != null && deal.AutoDeal.URMApproval.Any())
                {
                    var urmApproval = UrmApprovalStatusHelper.GetActualApproval(deal);
                    if (urmApproval != null)
                    {
                        kaskoDealDto.UrmStatus = urmApproval.URMApprovalStatusCode;
                        kaskoDealDto.UrmDescription = urmApproval.URMApprovalComment;
                    }
                }

                if (deal.AutoDeal.TryGetLastOtaApproval(out var otaApproval))
                {
                    kaskoDealDto.OtaStatus = otaApproval.OtaApprovalStatusCode;
                }

                FillUnderwriterStatus(kaskoDealDto, deal);
                SetUrmCoefficient(kaskoDealDto, deal);
                FillUnderwriterApproval(kaskoDealDto, deal);
                FillPreviousPolicyConditions(kaskoDealDto, deal, packets);

                if (deal.PaymentSchedule != null && deal.Invoices != null && deal.Invoices.Any())
                {
                    kaskoDealDto.PaymentSchedule = deal.Invoices.Select(i => new InvoiceStatusResponseDto
                    {
                        CreateDate = i.CreateDate,
                        Currency = i.CurrencyCode,
                        Number = i.Number,
                        PaymentType = i.PaymentTypeCode,
                        RepaymentDate = i.DateRepayment,
                        Sum = i.Sum,
                        Type = i.InvoiceTypeCode
                    }).ToList();
                }

                kaskoDealDto.IsProlongation = deal.IsProlongation;
                kaskoDealDto.IsSubscription = deal.AutoDeal?.IsSubscription ?? false;
            }

            return dealDto;
        }

        private void FillUnderwriterApproval(DiKaskoResponseDealDto kaskoDealDto, Deal deal)
        {
            if (deal?.AutoDeal?.DIUnderwriterApprovals?.Any() != true)
            {
                return;
            }

            kaskoDealDto.UnderwriterApprovals ??= new List<UnderwriterApprovalDto>();

            foreach (var item in deal.AutoDeal.DIUnderwriterApprovals)
            {
                kaskoDealDto.UnderwriterApprovals.Add(new UnderwriterApprovalDto()
                { 
                    ApprovalId = item.ApprovalId, 
                    Status = item.StatusCode, 
                    ThemeCode = item.ThemeCode,
                    RequestDescription = item.RequestDescription,
                    UnderwriterCommentary = item.Commentary,
                    AutoCostApproval = item.AutoCostApproval
                });
            }
        }

        private DealStatusResponseDto GetDealInfoB2B(DealStatusResponseDto dealDto, Deal deal, List<AvailablePacketDto> packets)
        {
            dealDto = base.GetDealInfo(dealDto, deal, packets);

            if (dealDto is DiKaskoResponseDealDto kaskoDealDto && deal.Product.ProductDictCode == "KASKO")
            {
                if (deal.AutoDeal.TryGetLastUrmApproval(out var approval))
                {
                    kaskoDealDto.UrmStatus = approval.URMApprovalStatusCode;
                }

                if (deal.AutoDeal.TryGetLastOtaApproval(out var otaApproval))
                {
                    kaskoDealDto.OtaStatus = otaApproval.OtaApprovalStatusCode;
                }

                var inspection = Mediator.ResolveQuery<IQueryKaskoInspection>().GetInspectionByDealEntityId(deal.EntityId);
                if (inspection != null)
                {
                    kaskoDealDto.PsoStatus = inspection.InspectionStatusCode;
                    kaskoDealDto.PsoStatusDescription = inspection.StatusChangeDescription;
                }

                FillUnderwriterStatus(kaskoDealDto, deal);
                SetAvailableCommissionValue(kaskoDealDto, deal);
                SetUrmCoefficient(kaskoDealDto, deal);
                FillPreviousPolicyConditionsB2B(kaskoDealDto, deal, packets);
                FillUnderwriterApproval(kaskoDealDto, deal);

                kaskoDealDto.IsProlongation = deal.IsProlongation;

                if (deal.PaymentSchedule != null && deal.Invoices != null && deal.Invoices.Any())
                {
                    kaskoDealDto.PaymentSchedule = deal.Invoices.Select(i => new InvoiceStatusResponseDto
                    {
                        CreateDate = i.CreateDate,
                        Currency = i.CurrencyCode,
                        Number = i.Number,
                        PaymentType = i.PaymentTypeCode,
                        RepaymentDate = i.DateRepayment,
                        Sum = i.Sum,
                        Type = i.InvoiceTypeCode
                    }).ToList();
                }
            }

            return dealDto;
        }

        private void FillMessagesDi(ResponseDto<ModelResponseDto> response, PipelineExecutionContext context, string commandName)
        {
            base.FillMessages(response, context, commandName);
            var processApiContext = context.ServiceProvider.GetService<ProcessApiContext>();
            if (context.ProcessName == "DiKaskoInsurance")
            {
                response.Messages = response
                    .Messages
                    .Distinct(new KaskoMessageResponseDtoEqualityComparer())
                    .ToList();

                if (processApiContext.Command is DIKaskoCalculationLink2Command)
                {
                    var basket = context.GetBasket();
                    var deal = basket.GetKaskoDeal();
                    var auto = deal.GetAuto();

                    if (auto.HasMileage == true)
                    {
                        response.Messages.Add(new MessageResponseDto()
                        {
                            Level = ResponseMessageLevel.Warning,
                            Text = "Оформление полиса возможно только при условии прохождения ПСО"
                        });
                    }

                    var partialStatuses = KaskoOsagoHelper.GetUnderwriterApprovalLink2AcceptedStatuses();
                    var partialUnderwriterApprovals = deal.AutoDeal?.DIUnderwriterApprovals?
                        .Where(o => o != null && partialStatuses.Contains(o.StatusCode))
                        .ToList();
                    if (partialUnderwriterApprovals != null && partialUnderwriterApprovals.Any(x => x.IsClosed != true))
                    {
                        partialUnderwriterApprovals.ForEach(p => response.Messages.Add(new MessageResponseDto
                        {
                            Level = ResponseMessageLevel.Warning,
                            Text = $"Ошибка прохождения андеррайтерских проверок: {p.Commentary}"
                        }));
                    }
                }

                if (processApiContext.Command is DIKaskoImportLink2Command)
                {
                    var basket = context.GetBasket();
                    var kaskoDeal = basket.GetKaskoDeal();

                    if (kaskoDeal.AutoDeal.TryGetLastUrmApproval(out var approval) && approval.URMApprovalStatusCode == UrmApprovalStatusCodes.Required)
                    {
                        response.Messages.Add(new MessageResponseDto
                        {
                            Level = ResponseMessageLevel.Info,
                            Text = @"Для проведения проверки УРМ необходимо приложить: паспорт Собственника и Страхователя; водительские удостоверения всех допущенных к управлению (если полис с ограничением ЛДУ); ПТС; СТС (если ТС не стоит на учете, ДКП); полис каско за прошлый год (если есть – необязательно)."
                        });
                    }

                    if (kaskoDeal.AutoDeal.TryGetLastOtaApproval(out var otaApproval) && otaApproval.OtaApprovalStatusCode == OtaApprovalStatusCodes.Required)
                    {
                        response.Messages.Add(new MessageResponseDto
                        {
                            Level = ResponseMessageLevel.Info,
                            Text = @"Для проведения проверки ОТА необходимо приложить: паспорт Собственника и Страхователя; водительские удостоверения всех допущенных к управлению (если полис с ограничением ЛДУ); ПТС; СТС (если ТС не стоит на учете, ДКП); полис каско за прошлый год (если есть – необязательно)."
                        });
                    }
                }

                if (processApiContext.Command is Link2GetStatusCommand || processApiContext.Command is DIKaskoContinueProcessLink2Command)
                {
                    var basket = context.GetBasket();
                    if (basket.GetKaskoDeal().AutoDeal.TryGetLastOtaApproval(out var otaApproval) && otaApproval.OtaApprovalStatusCode == OtaApprovalStatusCodes.Mistakes)
                    {
                        response.Messages.Add(new MessageResponseDto
                        {
                            Level = ResponseMessageLevel.Info,
                            Text = @"При проверке договора выявлены критичные ошибки. Для продолжения оформления необходимо исправить данные ошибки и направить договор на повторную проверку."
                        });
                        response.Messages.AddRange(otaApproval.OtaApprovalCheckErrors.Select(x => new MessageResponseDto
                        {
                            Level = ResponseMessageLevel.Info,
                            Text = $"{x.OtaApprovalMistake.Name}. Комментарий к ошибке по ОТА/ПСО: {x.ErrorComment}"
                        }));
                    }

                    if (basket.GetKaskoDeal().AutoDeal.TryGetLastUrmApproval(out var approval) && !string.IsNullOrEmpty(approval.URMApprovalComment))
                    {
                        response.Messages.Add(new MessageResponseDto
                        {
                            Level = ResponseMessageLevel.Info,
                            Text = $"Комментарий ОПККК: {approval.URMApprovalComment}"
                        });
                    }
                }
            }

            if (context.PipelineSharedVariables.ContainsKey(nameof(RecurringPaymentType)) &&
                !Enum.TryParse(context.PipelineSharedVariables[nameof(RecurringPaymentType)].ToString(), out RecurringPaymentType recurringPaymentType))
            {
                response.Messages.Add(new MessageResponseDto()
                {
                    Level = ResponseMessageLevel.Info,
                    Text = $"Неподходящие условия для использования рассрочки. {context.PipelineSharedVariables[nameof(RecurringPaymentType)]}"
                });
            }
        }

        private void FillMessagesB2B(ResponseDto<ModelResponseDto> response, PipelineExecutionContext context, string commandName)
        {
            base.FillMessages(response, context, commandName);

            var processApiContext = context.ServiceProvider.GetService<ProcessApiContext>();
            if (processApiContext.Command is DIKaskoImportLink2Command)
            {
                var basket = context.GetBasket();
                var kaskoDeal = basket.GetKaskoDeal();

                if (kaskoDeal.AutoDeal.TryGetLastUrmApproval(out var approval) && approval.URMApprovalStatusCode == UrmApprovalStatusCodes.Required)
                {
                    response.Messages.Add(new MessageResponseDto
                    {
                        Level = ResponseMessageLevel.Info,
                        Text = @"Для проведения проверки УРМ необходимо приложить: паспорт Собственника и Страхователя; водительские удостоверения всех допущенных к управлению (если полис с ограничением ЛДУ); ПТС; СТС (если ТС не стоит на учете, ДКП); полис каско за прошлый год (если есть – необязательно)."
                    });
                }

                if (kaskoDeal.AutoDeal.TryGetLastOtaApproval(out var otaApproval) && otaApproval.OtaApprovalStatusCode == OtaApprovalStatusCodes.Required)
                {
                    response.Messages.Add(new MessageResponseDto
                    {
                        Level = ResponseMessageLevel.Info,
                        Text = @"Для проведения проверки ОТА необходимо приложить: паспорт Собственника и Страхователя; водительские удостоверения всех допущенных к управлению (если полис с ограничением ЛДУ); ПТС; СТС (если ТС не стоит на учете, ДКП); полис каско за прошлый год (если есть – необязательно)."
                    });
                }

                var inspection = Mediator.ResolveQuery<IQueryKaskoInspection>().GetInspectionByDealEntityId(kaskoDeal.EntityId);
                if (inspection != null)
                {
                    response.Messages.Add(new MessageResponseDto
                    {
                        Level = ResponseMessageLevel.Info,
                        Text = @"Для проведения проверки ПСО необходимо приложить: фотографии автомобиля."
                    });
                }
            }

            if (processApiContext.Command is Link2GetStatusCommand || processApiContext.Command is DIKaskoContinueProcessLink2Command)
            {
                var basket = (Basket)context.Entities["Basket"];
                if (basket.GetKaskoDeal().AutoDeal.TryGetLastOtaApproval(out var otaApproval) && otaApproval.OtaApprovalStatusCode == OtaApprovalStatusCodes.Mistakes)
                {
                    response.Messages.Add(new MessageResponseDto
                    {
                        Level = ResponseMessageLevel.Info,
                        Text = @"При проверке договора выявлены критичные ошибки. Для продолжения оформления необходимо исправить данные ошибки и направить договор на повторную проверку."
                    });
                    response.Messages.AddRange(otaApproval.OtaApprovalCheckErrors.Select(x => new MessageResponseDto
                    {
                        Level = ResponseMessageLevel.Info,
                        Text = $"{x.OtaApprovalMistake.Name}. Комментарий к ошибке по ОТА/ПСО: {x.ErrorComment}"
                    }));
                }

                if (basket.GetKaskoDeal().AutoDeal.BamIntegrationLog.Any())
                {
                    response.Messages.Add(new MessageResponseDto
                    {
                        Level = ResponseMessageLevel.Info,
                        Text = $"Оригинал квитанции А7 недоступен в связи с: {basket.GetKaskoDeal().AutoDeal.BamIntegrationLog.First().ErrorMessage}"
                    });
                }

                if (basket.GetKaskoDeal().AutoDeal.TryGetLastUrmApproval(out var approval) && !string.IsNullOrEmpty(approval.URMApprovalComment))
                {
                    response.Messages.Add(new MessageResponseDto
                    {
                        Level = ResponseMessageLevel.Info,
                        Text = $"Комментарий ОПККК: {approval.URMApprovalComment}"
                    });
                }
            }
        }
    }
}

Мне надо понять где проставляется urm статус?