Реализована логика отмены новых запросов

parent 32596a33
......@@ -35,10 +35,7 @@
</providers>
</configProtectedData>
<connectionStrings>
<clear />
<add name="RDnLContext" connectionString="metadata=res://RnD.Model.EF/RnDConnection.csdl|res://RnD.Model.EF/RnDConnection.ssdl|res://RnD.Model.EF/RnDConnection.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=LLK-DEV\;initial catalog=OpcenterRDnL;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
<add name="RDnLContext2" connectionString="metadata=res://*/RnDConnection.csdl|res://*/RnDConnection.ssdl|res://*/RnDConnection.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=LLK-DEV\;initial catalog=OpcenterRDnL;User=RDnLAppUser;Password=pass@word1;multipleactiveresultsets=True;application name=EntityFramework&quot;" providerName="System.Data.EntityClient" />
<add name="OpcenterRDnL" connectionString="metadata=res://*/RnDConnection.csdl|res://*/RnDConnection.ssdl|res://*/RnDConnection.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=LLK-DEV\;initial catalog=OpcenterRDnL;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>
<appSettings>
<add key="Resources" value="%public%\OpcenterRDnL\Resources" />
......
......@@ -5,7 +5,7 @@ using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
namespace ProfitGroup.SampleNotifyService.Core.Auth
namespace ProfitGroup.NotifyService.Core.Auth
{
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
......
......@@ -33,12 +33,12 @@
"writeTo": "allfile"
},
{
"logger": "ProfitGroup.SampleNotifyService.*",
"logger": "ProfitGroup.NotifyService.*",
"minLevel": "Trace",
"writeTo": "requests-web"
},
{
"logger": "ProfitGroup.SampleNotifyService.Core.Auth.*",
"logger": "ProfitGroup.NotifyService.Core.Auth.*",
"minLevel": "Trace",
"writeTo": "requests-web"
}
......
......@@ -7,7 +7,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProfitGroup.SampleService.C
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProfitGroup.Rdnl.Extensions", "ProfitGroup.Rdnl.Extensions\ProfitGroup.Rdnl.Extensions.csproj", "{CE66275C-0543-46D5-8DF7-0EC58562F408}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProfitGroup.SampleNotifyService", "ProfitGroup.SampleNotifyService\ProfitGroup.SampleNotifyService.csproj", "{9CC9E1EE-03E6-44BA-A461-7C2034921970}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProfitGroup.NotifyService", "ProfitGroup.NotifyService\ProfitGroup.NotifyService.csproj", "{9CC9E1EE-03E6-44BA-A461-7C2034921970}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProfitGroup.SampleRequest", "ProfitGroup.SampleRequest\ProfitGroup.SampleRequest.csproj", "{DD05EABA-B6DA-4BE0-8B53-9D659D5CC786}"
EndProject
......
......@@ -7,8 +7,11 @@ using RnD.BusinessLayer.EF.Factory;
using RnD.BusinessLayer.EF.Interfaces;
using RnD.Model.EF;
using System;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Web.Http;
using ProfitGroup.SampleService.Models;
using Unity;
using Unity.Injection;
using Unity.Lifetime;
......@@ -19,32 +22,39 @@ namespace ProfitGroup.SampleService
{
public static class UnityConfig
{
public static UnityContainer Container;
public static void RegisterComponents()
{
var container = new UnityContainer();
Container = new UnityContainer();
var loggerConfig = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "nlog.config");
LogManager.Setup().LoadConfigurationFromFile(loggerConfig);
LogManager.Configuration = new XmlLoggingConfiguration(loggerConfig);
container.RegisterInstance(typeof(ILogger), LogManager.GetCurrentClassLogger());
// container.RegisterInstance(typeof(RDnLManager), new RDnLManager("OpcenterRDnL", "scCreate").Initialize(), lifetimeManager: new TransientLifetimeManager());
Container.RegisterInstance(typeof(ILogger), LogManager.GetCurrentClassLogger());
container.RegisterType<RDnLManager>(
Container.RegisterType<RDnLManager>(
new TransientLifetimeManager(),
new InjectionConstructor("OpcenterRDnL", "scCreate")
);
container.RegisterType<IKSSSInfoService, KsssInfoService>();
container.RegisterType<ISampleService, Core.Services.SampleService>();
container.RegisterInstance(typeof(SampleConfirmationService));
Container.RegisterType<IKSSSInfoService, KsssInfoService>();
Container.RegisterType<ISampleService, Core.Services.SampleService>();
Container.RegisterInstance(typeof(SampleCreateState), new SampleCreateState(), new SingletonLifetimeManager());
Container.RegisterInstance(typeof(SampleConfirmationService));
Container.RegisterSingleton<QueueHandler>();
var manager = Container.Resolve<RDnLManager>();
Container.RegisterInstance(typeof(API), new API(new BusinessObjectFactory(aConnection: (ISession<RnDConnection>)manager.EventAwareObjectFactory.FactorySession)));
var manager = container.Resolve<RDnLManager>();
var queueHandler = Container.Resolve<QueueHandler>();
container.RegisterInstance(typeof(API), new API(new BusinessObjectFactory(aConnection: (ISession<RnDConnection>)manager.EventAwareObjectFactory.FactorySession)));
queueHandler.StartProcessing();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(Container);
}
}
}
\ No newline at end of file
......@@ -3,55 +3,103 @@ using System.Text;
using System.Web;
using System.Net;
using System.Security.Principal;
using Microsoft.Extensions.Logging;
using NLog.Config;
using System.IO;
using NLog;
namespace ProfitGroup.SampleService.Core.Middlewares
{
/// <summary>
/// Представляет промежуточное ПО для базовой аутентификации.
/// </summary>
public class BasicAuthMiddleware : IHttpModule
{
private static NLog.ILogger Logger
{
get
{
var loggerConfig = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "nlog.config");
LogManager.Setup().LoadConfigurationFromFile(loggerConfig);
LogManager.Configuration = new XmlLoggingConfiguration(loggerConfig);
return LogManager.GetCurrentClassLogger();
}
}
//private readonly ILogger _logger;
//public BasicAuthMiddleware(ILoggerFactory loggerFactory)
//{
// _logger = loggerFactory.CreateLogger(typeof(BasicAuthMiddleware));
//}
/// <summary>
/// Инициализирует промежуточное ПО и подписывает обработчик события аутентификации запроса.
/// </summary>
public void Init(HttpApplication context)
{
context.AuthenticateRequest += OnAuthenticateRequest;
}
/// <summary>
/// Освобождает ресурсы, используемые промежуточным ПО.
/// </summary>
public void Dispose()
{
}
/// <summary>
/// Обработчик события аутентификации запроса.
/// </summary>
private void OnAuthenticateRequest(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
string authHeader = context.Request.Headers["Authorization"];
var authHeader = context.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Basic"))
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Basic"))
{
Logger.Error("Авторизация пропущена. Передан пустой Basic Auth Header");
return;
}
var encodedCredentials = authHeader.Substring("Basic".Length).Trim();
var credentialsBytes = Convert.FromBase64String(encodedCredentials);
var credentials = Encoding.ASCII.GetString(credentialsBytes);
var usernamePassword = credentials.Split(':');
if (usernamePassword.Length != 2) return;
var username = usernamePassword[0];
var password = usernamePassword[1];
if (IsUserValid(username, password))
{
Logger.Info("Успешная авторизация");
context.User = new GenericPrincipal(new GenericIdentity(username), null);
}
else
{
string encodedCredentials = authHeader.Substring("Basic".Length).Trim();
byte[] credentialsBytes = Convert.FromBase64String(encodedCredentials);
string credentials = Encoding.ASCII.GetString(credentialsBytes);
string[] usernamePassword = credentials.Split(':');
if (usernamePassword.Length == 2)
{
string username = usernamePassword[0];
string password = usernamePassword[1];
if (IsUserValid(username, password))
{
context.User = new GenericPrincipal(new GenericIdentity(username), null);
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Response.AddHeader("WWW-Authenticate", "Basic realm=\"Your Realm\"");
context.Response.End();
}
}
Logger.Error("Ошибка авторизации, неверный логин или пароль");
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Response.AddHeader("WWW-Authenticate", "Basic realm=\"Your Realm\"");
context.Response.End();
}
}
/// <summary>
/// Проверяет, является ли пользователь допустимым.
/// </summary>
private bool IsUserValid(string username, string password)
{
return username == "111" && password == "111";
// ToDo: Сменить пароль при переносе решения
// APP02
return username == "S4test" && password == "Era7%agEr12#L";
// Productive
// return username == "S4test" && password == "lMxeTqMIH04R8mCE";
}
}
}
\ No newline at end of file
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using NLog;
using NLog.Config;
using ProfitGroup.Rdnl.Extensions;
using ProfitGroup.SampleService.Models;
using Unity;
namespace ProfitGroup.SampleService.Core.Middlewares
{
public class SampleMiddleware : IHttpModule
{
private readonly SampleCreateState _sampleCreateState;
private static NLog.ILogger Logger
{
get
{
var loggerConfig = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "nlog.config");
LogManager.Setup().LoadConfigurationFromFile(loggerConfig);
LogManager.Configuration = new XmlLoggingConfiguration(loggerConfig);
return LogManager.GetCurrentClassLogger();
}
}
public SampleMiddleware()
{
_sampleCreateState = UnityConfig.Container?.Resolve<SampleCreateState>();
}
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AuthenticateRequest += OnAuthenticateRequest;
}
private void OnAuthenticateRequest(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
if (_sampleCreateState != null && _sampleCreateState.IsProcessing)
{
var message = "Был получен запрос, во время создания другой пробы. Запрос был отменен.";
Logger.Error(message);
context.Response.Output.Write(message);
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
context.Response.End();
}
}
}
}
\ No newline at end of file
namespace ProfitGroup.SampleService.Core.Services
{
/// <summary>
/// Предоставляет сервис для определения упаковки по значению диапазона.
/// </summary>
public class DetectPackageServiceByRangeValue
{
/// <summary>
/// Определяет упаковку на основе переданных значений диапазона и текущего значения.
/// </summary>
/// <param name="minPackageName">Наименование упаковки для минимального значения.</param>
/// <param name="maxPackageName">Наименование упаковки для максимального значения.</param>
/// <param name="maxValue">Максимальное значение диапазона.</param>
/// <param name="currentValue">Текущее значение для определения упаковки.</param>
/// <returns>Наименование определенной упаковки.</returns>
public static string Detect(
string minPackageName,
string maxPackageName,
......
......@@ -7,22 +7,68 @@ using ProfitGroup.SampleService.Data.Database.Entities;
namespace ProfitGroup.SampleService.Core.Services
{
/// <summary>
/// Предоставляет интерфейс сервиса для работы с информацией о КССС.
/// </summary>
public interface IKSSSInfoService
{
Task<ISpecification> FindActiveSpecificationById(decimal specificationId);
/// <summary>
/// Асинхронно находит активную спецификацию по идентификатору.
/// </summary>
Task<ISpecification> FindActiveSpecificationById(decimal specificationId, decimal sP_VERSION);
/// <summary>
/// Асинхронно получает информационные поля по коду КССС.
/// </summary>
Task<List<RndvSpIi>> GetInfoFieldsByKSSSCode(string ksssCode);
/// <summary>
/// Получает код продукта из спецификации КССС и возвращает идентификатор рамы.
/// </summary>
string GetProductCodeFromSpecificationKSSS(ISpecification specification, out decimal? frameId);
/// <summary>
/// Получает наименование упаковки из спецификации КССС.
/// </summary>
string GetPackageNameFromSpecificationKSSS(ISpecification specification);
/// <summary>
/// Получает наименования местоположения из спецификации.
/// </summary>
IEnumerable<string> GetSpecificationLocationName(ISpecification specification);
/// <summary>
/// Асинхронно выполняет отображение операционного контроля для указанного местоположения, рамы и типа инспекции.
/// </summary>
Task<S4InspectionTypeMap> MapOperationControl(decimal locationId, decimal? frameId, string inspectonType);
/// <summary>
/// Получает SampleType по коду продукта, наименованию операционного контроля, упаковке, стадии и идентификатору завода.
/// </summary>
RndvSt GetSampleType(string productCode, string operationControlName, string package, string stage,
decimal plantId);
/// <summary>
/// Асинхронно получает объект завода по его наименованию.
/// </summary>
Task<RndvLo> GetPlantByName(string plant);
/// <summary>
/// Асинхронно получает тип контроля по коду контроля.
/// </summary>
Task<SiemtControlTypes> GetControlTypeByCode(string controlTypeCode);
/// <summary>
/// Асинхронно получает объект завода по его идентификатору.
/// </summary>
Task<RndvLo> GetPlantById(decimal plantId);
/// <summary>
/// Проверка на существование в системе упаковки с текущим наименованием
/// </summary>
/// <param name="package">Наименование упаковки KSSS</param>
/// <param name="opCenterPackageName">Наименвоание упаковки из Opcenter</param>
/// <returns></returns>
bool CheckAndMapPackageName(string package, decimal plantId, out string opCenterPackageName);
Task<List<RndvSp>> GetActiveSpecificationsFromRange(List<decimal> specificationSp);
}
}
\ No newline at end of file
}
using ProfitGroup.SampleService.Models;
using RnD.BusinessLayer.Interfaces.Model;
using System.Net;
using System.Threading.Tasks;
namespace ProfitGroup.SampleService.Core.Services
{
/// <summary>
/// Предоставляет интерфейс сервиса подтверждения образца, ответственного за отправку сообщений в шину SAP/S4.
/// </summary>
public interface ISampleConfirmationService
{
Task<bool> SendConfirmationToSap(MT_InspLot mtInspLot, SampleFullDTO sampleFullDto, bool isSuccessCreated);
/// <summary>
/// Асинхронно отправляет подтверждение в SAP/S4.
/// </summary>
/// <param name="mtInspLot">Экземпляр класса MT_InspLot полученное от SAP/S4.</param>
/// <param name="sampleFullDto">DTO с полной информацией об образце.</param>
/// <param name="isSuccessCreated">Флаг успешного создания образца.</param>
/// <param name="message">Дополнительное сообщение.</param>
/// <returns>True, если операция отправки подтверждения выполнена успешно, в противном случае - false.</returns>
Task<(bool isSuccess, HttpStatusCode statusCode, string message)> SendConfirmationToSap(MT_InspLot mtInspLot, SampleFullDTO sampleFullDto, bool isSuccessCreated, string message = null);
}
}
}
\ No newline at end of file
......@@ -2,14 +2,45 @@
using RnD.BusinessLayer.Interfaces.Model;
using System.Collections.Generic;
using System.Threading.Tasks;
using RnD.Model;
namespace ProfitGroup.SampleService.Core.Services
{
/// <summary>
/// Предоставляет интерфейс сервиса образцов.
/// </summary>
public interface ISampleService
{
/// <summary>
/// Получает ключи задач для фильтрации по наименованию завода, наименованию операционного контроля и упаковке или стадии.
/// </summary>
/// <param name="plantName">Наименование завода.</param>
/// <param name="operationControlName">Наименование операционного контроля.</param>
/// <param name="packageOrStage">Наименование упаковки или стадии.</param>
/// <returns>Перечисление ключей задач для фильтрации.</returns>
IEnumerable<TaskFilterDTO> GetTaskKeys(string plantName, string operationControlName, string packageOrStage);
void FillSampleInfoCards(decimal sampleId, List<InfoCardSetting> infoCards);
/// <summary>
/// Заполняет информационные карточки образца.
/// </summary>
/// <param name="sample">Проба</param>
/// <param name="infoCards">Список настроек информационных карточек.</param>
/// <param name="plantName">Наименование завода.</param>
void FillSampleInfoCards(Sample sample, List<InfoCardSetting> infoCards, string plantName);
/// <summary>
/// Асинхронно выполняет валидацию образца по его краткому описанию.
/// </summary>
/// <param name="shortDescription">Краткое описание образца.</param>
/// <returns>True, если образец валиден, в противном случае - false.</returns>
Task<bool> ValidateSample(string shortDescription);
Task SendConfirmation(MT_InspLot shortDescription, SampleFullDTO sampleFullDto);
/// <summary>
/// Асинхронно отправляет подтверждение образца.
/// </summary>
/// <param name="mtInspLot">Экземпляр класса MT_InspLot для отправки.</param>
/// <param name="sampleFullDto">DTO с полной информацией об образце.</param>
/// <param name="message">Дополнительное сообщение.</param>
Task SendConfirmation(MT_InspLot mtInspLot, SampleFullDTO sampleFullDto, string message = null);
}
}
\ No newline at end of file
}
......@@ -18,6 +18,8 @@ using System.Data;
using System.Data.SqlTypes;
using NLog.Config;
using System.IO;
using System.Runtime.CompilerServices;
using ProfitGroup.SampleService.Models.Entities;
namespace ProfitGroup.SampleService.Core.Services
{
......@@ -44,24 +46,26 @@ namespace ProfitGroup.SampleService.Core.Services
_databaseContext = ((ISession<RnDConnection>)manager.EventAwareObjectFactory.FactorySession).Context;
}
public async Task<ISpecification> FindActiveSpecificationById(decimal specificationId)
public async Task<ISpecification> FindActiveSpecificationById(decimal specificationId, decimal specificationVersion)
{
var activeSpecification = await _databaseContext.RndvSp.FirstAsync(c =>
c.SP == specificationId
&& c.ACTIVE_STR == "1"
);
//var activeSpecification = await _databaseContext.RndvSp.FirstOrDefaultAsync(c =>
// c.SP == specificationId
// && c.ACTIVE_STR == "1"
// );
return _api.Specification.GetSpecification(activeSpecification.SP, activeSpecification.SP_VERSION);
//if (activeSpecification == null)
// return null;
return _api.Specification.GetSpecification(specificationId, specificationVersion);
}
public Task<List<RndvSpIi>> GetInfoFieldsByKSSSCode(string ksssCode)
{
// ToDo: Вынести константу KD_KSSS в конфиг + Проверить различные сценарии, когда обновляется Frame, создается ли новая версия инфополя?
return _databaseContext.RndvSpIi.Where(c =>
c.II_SHORT_DESC_MAIN == "KD_KSSS"
&& c.IIVALUE_MAIN == ksssCode
//c.ACTIVE_STR == "1"
//&& c.ACTIVE_STR == "1"
).ToListAsync();
}
......@@ -76,11 +80,11 @@ namespace ProfitGroup.SampleService.Core.Services
var kssInfoGroup =
specification.InfoCards.FirstOrDefault(c =>
c.ShortDescription == "KSSS_Data"); //ToDo: Вынести константу в конфиг
c.ShortDescription == "KSSS_Data");
var infoField =
kssInfoGroup?.InfoFields.FirstOrDefault(c =>
c.ShortDescription == "KD_Pack"); //ToDo: Вынести константу в конфиг
c.ShortDescription == "KD_Pack");
return infoField != null ? infoField.InfoFieldValue : string.Empty;
}
......@@ -116,11 +120,11 @@ namespace ProfitGroup.SampleService.Core.Services
// Id Frame: PackagedRM
var kssInfoGroup =
specification.InfoCards.FirstOrDefault(c =>
c.ShortDescription == "KSSS_RM_SKU"); //ToDo: Вынести константу в конфиг
c.ShortDescription == "KSSS_RM_SKU");
var infoField =
kssInfoGroup?.InfoFields.FirstOrDefault(c =>
c.ShortDescription == "KSSS_RM_ID"); //ToDo: Вынести константу в конфиг
c.ShortDescription == "KSSS_RM_ID");
return infoField?.InfoFieldValue;
}
......@@ -131,11 +135,11 @@ namespace ProfitGroup.SampleService.Core.Services
var kssInfoGroup =
specification.InfoCards.FirstOrDefault(c =>
c.ShortDescription == "KSSS_SKU"); //ToDo: Вынести константу в конфиг
c.ShortDescription == "KSSS_SKU");
var infoField =
kssInfoGroup?.InfoFields.FirstOrDefault(c =>
c.ShortDescription == "SKU_KsssProductCode"); //ToDo: Вынести константу в конфиг
c.ShortDescription == "SKU_KsssProductCode");
return infoField?.InfoFieldValue;
}
......@@ -154,7 +158,7 @@ namespace ProfitGroup.SampleService.Core.Services
return Enumerable.Empty<string>();
}
public async Task<S4InspectionTypeMap> MapOperationControl(decimal locationId, decimal? frameId, string inspectonType)
public async Task<S4InspectionTypeMap> MapOperationControl(decimal locationId, decimal? frameId, string inspectionType)
{
//var sql = "SELECT * FROM [ProfIT].[S4InspectionTypeMap] " +
// "WHERE [ProfIT].[S4InspectionTypeMap].[LO] = @location " +
......@@ -193,7 +197,7 @@ namespace ProfitGroup.SampleService.Core.Services
var sqlParameters = new List<SqlParameter>
{
new SqlParameter("@location", locationId.ToString()),
new SqlParameter("@inspectonType", inspectonType)
new SqlParameter("@inspectonType", inspectionType)
};
if (frameId != null)
......@@ -244,6 +248,7 @@ namespace ProfitGroup.SampleService.Core.Services
&& (c.SampleTypeAu.VALUE_MAIN.Contains(operationControlName) || c.SampleTypeAu.VALUE_MAIN == productCode)
).ToList();
// Если указана упаковка, дополнительно сортируем по Упаковке
if (!string.IsNullOrEmpty(package))
{
sampleTypes = _databaseContext.RndvSt.Join(_databaseContext.RndvStAu,
......@@ -258,7 +263,8 @@ namespace ProfitGroup.SampleService.Core.Services
&& (c.SampleTypeAu.VALUE_MAIN.Contains(operationControlName) || c.SampleTypeAu.VALUE_MAIN == productCode || c.SampleTypeAu.VALUE_MAIN == package)
).ToList();
}
// Если указана стадия, дополнительно сортируем по Упаковке
if (!string.IsNullOrEmpty(stage))
{
sampleTypes = _databaseContext.RndvSt.Join(_databaseContext.RndvStAu,
......@@ -278,6 +284,11 @@ namespace ProfitGroup.SampleService.Core.Services
sampleTypes = sampleTypes
.Where(c => c.SampleType.RndvStLo.FirstOrDefault(g => g.LO == plantId) != null)
.ToList();
// Отбираем объекты, у которых нет %-SP SP_%
sampleTypes = sampleTypes
.Where(c => c.SampleType.SHORT_DESC_MAIN.EndsWith("-SP") == false && c.SampleType.SHORT_DESC_MAIN.StartsWith("SP_") == false)
.ToList();
// Проверяем, что было совпадение по двум параметрам (operationControlName и productCode)
// Или трём, если был передан упаковка или стадия
......@@ -289,11 +300,12 @@ namespace ProfitGroup.SampleService.Core.Services
.Select(c => c.FirstOrDefault())
.ToList();
// Если мы нашли только один SampleType по количеству переданных атрибутов
if (groupingSampleTypes.Count == 1)
return groupingSampleTypes.Single().SampleType;
Logger.Error(
$"В результате получения SampleType было получено несколько возможных вариантов: {string.Join(",", sampleTypes.Select(c => $"{c.SampleType.ST} / {c.SampleType.SHORT_DESC_MAIN}"))}");
$"В результате получения SampleType было получено несколько возможных вариантов: {string.Join(",", groupingSampleTypes.Select(c => $"{c.SampleType.ST} / {c.SampleType.SHORT_DESC_MAIN}"))}");
return null;
}
......@@ -302,5 +314,56 @@ namespace ProfitGroup.SampleService.Core.Services
{
return await _databaseContext.RndvLo.FirstOrDefaultAsync(c => c.SHORT_DESC_MAIN == plant);
}
public async Task<RndvLo> GetPlantById(decimal plantId)
{
return await _databaseContext.RndvLo.FirstOrDefaultAsync(c => c.LO == plantId);
}
public bool CheckAndMapPackageName(string package, decimal plantId, out string opCenterPackageName)
{
var mappedPack = _databaseContext.Database.SqlQuery<RndtpackMapObject>("SELECT * FROM [RndSuite].[RndtpackKSSSMap] WHERE PackKSSS = @packName AND LocationId = @location", new SqlParameter("packName", package), new SqlParameter("location", plantId)).FirstOrDefault();
if (mappedPack != null)
{
opCenterPackageName = mappedPack.Pack;
return true;
#region oldCode
// var rndtPackOriginal = _databaseContext.Database.SqlQuery<Rndtpack>("SELECT * FROM [RndSuite].[Rndtpack] WHERE pack = @packName", new SqlParameter("packName", package)).FirstOrDefault();
//
// if (rndtPackOriginal == null)
// {
//
//
// opCenterPackageName = mappedPack.Pack;
//
// return true;
//
// }
// else
// {
// opCenterPackageName = rndtPackOriginal.pack;
//
// return true;
// }
// opCenterPackageName = string.Empty;
// return false;
#endregion
}
opCenterPackageName = string.Empty;
return false;
}
public Task<List<RndvSp>> GetActiveSpecificationsFromRange(List<decimal> specificationIDs)
{
return _databaseContext.RndvSp.Where(c => specificationIDs.Contains(c.SP) && c.ACTIVE_STR == "1").ToListAsync();
}
}
}
\ No newline at end of file
......@@ -6,9 +6,12 @@ using ProfitGroup.SampleService.Models;
using RnD.API;
using RnD.BusinessLayer.Interfaces.Model;
using System;
using System.Buffers.Text;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
......@@ -38,23 +41,29 @@ namespace ProfitGroup.SampleService.Core.Services
_appSettings = JsonConvert.DeserializeObject<Appsettings>(File.ReadAllText(path));
}
public async Task<bool> SendConfirmationToSap(MT_InspLot content, SampleFullDTO sampleFullDto, bool isSuccessCreated)
public async Task<(bool isSuccess, HttpStatusCode statusCode, string message)> SendConfirmationToSap(MT_InspLot content, SampleFullDTO sampleFullDto,
bool isSuccessCreated, string message = null)
{
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = BasicAuthorization(_appSettings.ConfirmationLogin, _appSettings.ConfirmationPassword);
client.DefaultRequestHeaders.Add("SOAPAction", " http://sap.com/xi/WebService/soap1.1 ");
if (string.IsNullOrEmpty(message))
message = isSuccessCreated ? $@"Проба сформирована успешно" : "Проба не была сформирована";
client.BaseAddress = new Uri(_appSettings.ConfirmationUrl);
var dto = new Models.Confirmation.Document
{
Status = isSuccessCreated ? "S" : "E",
StatusText = isSuccessCreated ? $@"Проба сформирована успешно" : "Проба не была сформирована",
SC_VALUE = sampleFullDto.ShortDescription,
ControlPartionId = content.Document.InspectionLot,
StatusText = message,
SC_VALUE = sampleFullDto?.ID.Value.ToString() ?? string.Empty,
ControlPartionId = content?.Document?.InspectionLot,
LineId = "1",
ProbeId = sampleFullDto.ID.ToString()
ProbeId = content?.Document?.Proba
};
var data = new Models.Confirmation.Envelope
......@@ -64,6 +73,7 @@ namespace ProfitGroup.SampleService.Core.Services
MT_InspLotConf = new Models.Confirmation.MT_InspLotConf
{
Document = dto,
GuidMsgOutb = content?.GuigMsgOutb
}
}
};
......@@ -74,27 +84,53 @@ namespace ProfitGroup.SampleService.Core.Services
var serializer = new XmlSerializer(typeof(Models.Confirmation.Envelope));
using (var stringWriter = new StringWriter())
using (var stringWriter = new StringWriterUTF8())
{
serializer.Serialize(stringWriter, data, namespaces);
var xmlString = stringWriter.ToString();
// ToDo: Заменить ендпоинт
var request = await client.PostAsync("/XISOAPAdapter/MessageServlet?senderParty=&senderService=BSP_OPCENTER&receiverParty=&receiverService=&interface=SI_OpCenterSend_AO&interfaceNamespace=http://lukoil.ru/opcenter/ORM", new StringContent(xmlString, Encoding.UTF8));
return request.IsSuccessStatusCode;
if (Directory.Exists(_appSettings.XmlConfirmationDirectory) == false)
Directory.CreateDirectory(_appSettings.XmlConfirmationDirectory);
if (!string.IsNullOrEmpty(content.GuigMsgOutb))
File.WriteAllText(Path.Combine(_appSettings.XmlConfirmationDirectory, $"{content.GuigMsgOutb}.xml"), xmlString);
else
Logger.Error($"Был получен пустой Message guid");
// ToDo: Заменить ендпоинт
//Dev
var request = await client.PostAsync("/XISOAPAdapter/MessageServlet?senderParty=&senderService=BSD_OPCENTER&receiverParty=&receiverService=&interface=SI_OpCenterSend_AO&interfaceNamespace=http%3A%2F%2Flukoil.ru%2Fopcenter%2FORM", new StringContent(xmlString, Encoding.UTF8, "text/xml"));
//Prod
// var request = await client.PostAsync("/XISOAPAdapter/MessageServlet?senderParty=&senderService=BSP_OPCENTER&receiverParty=&receiverService=&interface=SI_OpCenterSend_AO&interfaceNamespace=http://lukoil.ru/opcenter/ORM", new StringContent(xmlString, Encoding.UTF8, "text/xml"));
//Test
// var request = await client.PostAsync("/MessageServlet?senderParty=&senderService=BST_OPCENTER&receiverParty=&receiverService=&interface=SI_OpCenterSend_AO&interfaceNamespace=http%3A%2F%2Flukoil.ru%2Fopcenter%2FORM", new StringContent(xmlString, Encoding.UTF8, "text/xml"));
var result = await request.Content.ReadAsStringAsync();
return (request.IsSuccessStatusCode, request.StatusCode, result);
}
}
}
catch (Exception ex)
{
Logger.Error(ex);
return false;
return (false, HttpStatusCode.NoContent, string.Empty);
}
}
public AuthenticationHeaderValue BasicAuthorization(string login, string password)
{
var authenticationString = $"{login}:{password}";
var base64EncodedAuthenticationString = Convert.ToBase64String(Encoding.ASCII.GetBytes(authenticationString));
return new AuthenticationHeaderValue("Basic", base64EncodedAuthenticationString);
}
}
}
\ No newline at end of file
using System.Collections.Generic;
using Newtonsoft.Json;
namespace ProfitGroup.SampleService.Models
{
/// <summary>
/// Представляет настройки для инфокарт, определяющие значение поля, путь и атрибуты, которые записываются в инфокарту из пакета.
/// </summary>
public class InfoCardSetting
{
public string Name { get; set; }
public string InfoCard { get; set; }
public string InfoField { get; set; }
/// <summary>
/// Получает или устанавливает имя атрибута.
/// </summary>
[JsonProperty("Name")] public string Name { get; set; }
/// <summary>
/// Получает или устанавливает значение атрибута "Plant".
/// </summary>
[JsonProperty("Plant")] public string Plant { get; set; }
/// <summary>
/// Получает или устанавливает значение атрибута "Value".
/// </summary>
public string Value { get; set; }
/// <summary>
/// Получает или устанавливает список путей к полям инфокарты.
/// </summary>
[JsonProperty("InfoFieldPaths")] public List<InfoFieldPath> InfoFieldPaths { get; set; }
}
/// <summary>
/// Представляет путь к полю инфокарты, состоящий из имени инфокарты и имени поля.
/// </summary>
public class InfoFieldPath
{
/// <summary>
/// Получает или устанавливает имя инфокарты.
/// </summary>
[JsonProperty("InfoCard")] public string InfoCard { get; set; }
/// <summary>
/// Получает или устанавливает имя поля инфокарты.
/// </summary>
[JsonProperty("InfoField")] public string InfoField { get; set; }
}
/// <summary>
/// Представляет настройки приложения, такие как URL подтверждения, логин, пароль и директория подтверждения.
/// </summary>
public class Appsettings
{
public string ConfirmationUrl { get; set; }
public List<InfoCardSetting> InfoCardSettings { get; set; }
/// <summary>
/// Получает или устанавливает URL подтверждения.
/// </summary>
[JsonProperty("ConfirmationUrl")] public string ConfirmationUrl { get; set; }
/// <summary>
/// Получает или устанавливает логин подтверждения.
/// </summary>
[JsonProperty("ConfirmationLogin")] public string ConfirmationLogin { get; set; }
/// <summary>
/// Получает или устанавливает пароль подтверждения.
/// </summary>
[JsonProperty("ConfirmationPassword")] public string ConfirmationPassword { get; set; }
/// <summary>
/// Получает или устанавливает директорию подтверждения в формате XML.
/// </summary>
[JsonProperty("XmlConfirmationDirectory")]
public string XmlConfirmationDirectory { get; set; }
/// <summary>
/// Получает или устанавливает список настроек инфокарты.
/// </summary>
[JsonProperty("InfoCardSettings")] public List<InfoCardSetting> InfoCardSettings { get; set; }
}
}
\ No newline at end of file
}
......@@ -3,31 +3,58 @@ using System.Xml.Serialization;
namespace ProfitGroup.Rdnl.Extensions.Models
{
/// <summary>
/// Представляет корневой элемент MT_Confirmation с пространством имен "http://lukoil.ru/opcenter/ORM".
/// </summary>
[XmlRoot("MT_Confirmation", Namespace = "http://lukoil.ru/opcenter/ORM")]
public class MT_Confirmation
{
/// <summary>
/// Получает или устанавливает список подтверждений.
/// </summary>
[XmlElement("Confirmation")]
public List<Confirmation> Confirmations { get; set; }
}
/// <summary>
/// Представляет элемент подтверждения с пространством имен "http://lukoil.ru/opcenter/ORM".
/// </summary>
[XmlRoot("Confirmation", Namespace = "http://lukoil.ru/opcenter/ORM")]
public class Confirmation
{
/// <summary>
/// Получает или устанавливает значение атрибута "ObjectType".
/// </summary>
[XmlAttribute]
public string ObjectType { get; set; }
/// <summary>
/// Получает или устанавливает значение атрибута "ResponseType".
/// </summary>
[XmlAttribute]
public string ResponseType { get; set; }
/// <summary>
/// Получает или устанавливает значение атрибута "ID".
/// </summary>
[XmlAttribute]
public string ID { get; set; }
/// <summary>
/// Получает или устанавливает значение атрибута "Version".
/// </summary>
[XmlAttribute]
public string Version { get; set; }
/// <summary>
/// Получает или устанавливает значение атрибута "StatusCode".
/// </summary>
[XmlAttribute]
public string StatusCode { get; set; }
/// <summary>
/// Получает или устанавливает значение атрибута "StatusText".
/// </summary>
[XmlAttribute]
public string StatusText { get; set; }
}
......
......@@ -3,23 +3,59 @@ using System;
namespace ProfitGroup.SampleService.Models
{
/// <summary>
/// Представляет объект передачи данных (DTO) для создания пользовательского образца.
/// </summary>
public class CustomSampleCreateDto
{
/// <summary>
/// Получает или устанавливает наименование завода.
/// </summary>
public string PlantName { get; set; }
/// <summary>
/// Получает или устанавливает код продукта.
/// </summary>
public string ProductCode { get; set; }
/// <summary>
/// Получает или устанавливает упаковку образца.
/// </summary>
public string Package { get; set; }
/// <summary>
/// Получает или устанавливает раму спецификации.
/// </summary>
public string SpecificationFrame { get; set; }
/// <summary>
/// Получает или устанавливает наименование операции контроля.
/// </summary>
public string OperationControlName { get; set; }
/// <summary>
/// Получает или устанавливает тип образца.
/// </summary>
public RndvSt SampleType { get; set; }
}
/// <summary>
/// Представляет атрибут наименования операции контроля.
/// </summary>
public class OperationControlNameAttribute : Attribute
{
/// <summary>
/// Получает наименование операции контроля.
/// </summary>
public string Name { get; }
/// <summary>
/// Инициализирует новый экземпляр атрибута с указанным наименованием.
/// </summary>
/// <param name="name">Наименование операции контроля.</param>
public OperationControlNameAttribute(string name)
{
Name = name;
}
}
}
\ No newline at end of file
}
......@@ -13,6 +13,8 @@
//}
// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
......@@ -86,6 +88,8 @@
private Document documentField;
private string guidMsgOutbField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Namespace = "")]
public Document Document
......@@ -99,13 +103,27 @@
this.documentField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string GuidMsgOutb
{
get
{
return this.guidMsgOutbField;
}
set
{
this.guidMsgOutbField = value;
}
}
}
/// <remarks/>
[System.Serializable()]
[System.ComponentModel.DesignerCategory("code")]
[System.Xml.Serialization.XmlType(AnonymousType = true)]
[System.Xml.Serialization.XmlRoot(Namespace = "", IsNullable = false)]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class Document
{
......@@ -210,4 +228,5 @@
}
\ No newline at end of file
namespace ProfitGroup.SampleService.Models
{
public class SampleCreateState
{
public bool IsProcessing { get; set; }
}
}
\ No newline at end of file
......@@ -302,13 +302,21 @@
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\SampleController.cs" />
<Compile Include="Core\Middlewares\BasicAuthMiddleware.cs" />
<Compile Include="Core\Middlewares\SampleMiddleware.cs" />
<Compile Include="Core\Services\DetectPackageServiceByRangeValue.cs" />
<Compile Include="Core\Services\IKSSSInfoService.cs" />
<Compile Include="Core\Services\ISampleConfirmationService.cs" />
<Compile Include="Core\Services\ISampleService.cs" />
<Compile Include="Core\Services\KSSSInfoService.cs" />
<Compile Include="Core\Services\SampleConfirmationService.cs" />
<Compile Include="Core\Services\SampleService.cs" />
<Compile Include="Core\Services\KSSSInfoService.cs">
<DependentUpon>IKSSSInfoService.cs</DependentUpon>
</Compile>
<Compile Include="Core\Services\QueueHandler.cs" />
<Compile Include="Core\Services\SampleConfirmationService.cs">
<DependentUpon>ISampleConfirmationService.cs</DependentUpon>
</Compile>
<Compile Include="Core\Services\SampleService.cs">
<DependentUpon>ISampleService.cs</DependentUpon>
</Compile>
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
......@@ -316,9 +324,12 @@
<Compile Include="Models\ConfirmationRequest.cs" />
<Compile Include="Models\CreateSampleRequestDto.cs" />
<Compile Include="Models\CustomSampleCreateDto.cs" />
<Compile Include="Models\Entities\RndtPack.cs" />
<Compile Include="Models\Entities\SiemtControlTypes.cs" />
<Compile Include="Models\S4InspectionTypeMap.cs" />
<Compile Include="Models\SampleConfirmationDto.cs" />
<Compile Include="Models\SampleCreateState.cs" />
<Compile Include="Models\StringWriterUTF8.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
......@@ -389,9 +400,6 @@
<Content Include="Views\Shared\Error.cshtml" />
<Content Include="Views\Shared\_Layout.cshtml" />
</ItemGroup>
<ItemGroup>
<Folder Include="App_Data\" />
</ItemGroup>
<ItemGroup>
<Content Include="Scripts\bootstrap.min.js.map" />
</ItemGroup>
......
......@@ -2,7 +2,7 @@
<section class="row" aria-labelledby="aspnetTitle">
<h1 id="aspnetTitle">PROF-IT Group | Sample Service</h1>
<p class="lead">Сервис по созданию проб в RDnL Opcenter</p>
<p><a href="https://localhost:44395/Help" class="btn btn-primary btn-md">Перейти к документации API &raquo;</a></p>
<p><a href="/Help" class="btn btn-primary btn-md">Перейти к документации API &raquo;</a></p>
</section>
</main>
\ No newline at end of file
......@@ -77,6 +77,7 @@
</handlers>
<modules>
<add name="BasicAuthMiddleware" type="ProfitGroup.SampleService.Core.Middlewares.BasicAuthMiddleware"/>
<add name="SampleMiddleware" type="ProfitGroup.SampleService.Core.Middlewares.SampleMiddleware"/>
</modules>
</system.webServer>
<runtime>
......
This diff is collapsed.
......@@ -3,18 +3,21 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Warn"
internalLogFile="C:\111\temp\sample-service\${shortdate}\internal-nlog.txt">
internalLogFile="C:\Logs\S4ScCreateIn\internal-nlog.txt">
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<targets>
<target xsi:type="File" name="sampleService" fileName="C:\111\temp\sample-service\${shortdate}\requests.log"
<target xsi:type="File" name="sampleService" fileName="C:\Logs\S4ScCreateIn\${shortdate}\requests.log"
layout="${longdate}|${event-properties:item=EventId_Id}|${logger}|${level:uppercase=true}|${message} ${exception:format=tostring}" />
<target xsi:type="File" name="queueHandler" fileName="C:\Logs\S4ScCreateIn\${shortdate}\CreateSample.log"
layout="${longdate}|${event-properties:item=EventId_Id}|${logger}|${level:uppercase=true}|${message} ${exception:format=tostring}" />
</targets>
<rules>
<logger name="ProfitGroup.SampleService.*" minlevel="Trace" writeTo="sampleService" />
<logger name="ProfitGroup.SampleService.Core.Services.QueueHandler" minlevel="Trace" writeTo="queueHandler" />
<logger name="ProfitGroup.SampleService.*" minlevel="Trace" writeTo="sampleService" final="true"/>
</rules>
</nlog>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment