commit 829636b78cc0ea683f477f494c0915694486d0c8 Author: AnboevDD Date: Thu Jul 10 16:35:13 2025 +0500 Первый diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5a5f80a --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ + +#Ignore thumbnails created by Windows +Thumbs.db +#Ignore files built by Visual Studio +*.obj +*.exe +*.pdb +*.user +*.aps +*.pch +*.vspscc +*_i.c +*_p.c +*.ncb +*.suo +*.tlb +*.tlh +*.bak +*.cache +*.ilk +*.log +[Bb]in +[Dd]ebug*/ +*.lib +*.sbr +obj/ +[Rr]elease*/ +_ReSharper*/ +[Tt]est[Rr]esult* +.vs/ +#Nuget packages folder +packages/ diff --git a/HRM_MQ_Consumer_Service.sln b/HRM_MQ_Consumer_Service.sln new file mode 100644 index 0000000..6c3f10e --- /dev/null +++ b/HRM_MQ_Consumer_Service.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HRM_MQ_Consumer_Service", "HRM_MQ_Consumer_Service\HRM_MQ_Consumer_Service.csproj", "{4E5D446E-7AF9-490D-B503-59BCBFCCA63F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4E5D446E-7AF9-490D-B503-59BCBFCCA63F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E5D446E-7AF9-490D-B503-59BCBFCCA63F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E5D446E-7AF9-490D-B503-59BCBFCCA63F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4E5D446E-7AF9-490D-B503-59BCBFCCA63F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FE5F9BE8-894B-42E9-8127-8146CF8E0163} + EndGlobalSection +EndGlobal diff --git a/HRM_MQ_Consumer_Service/App.config b/HRM_MQ_Consumer_Service/App.config new file mode 100644 index 0000000..7253bcf --- /dev/null +++ b/HRM_MQ_Consumer_Service/App.config @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HRM_MQ_Consumer_Service/HRMConsumerService.Designer.cs b/HRM_MQ_Consumer_Service/HRMConsumerService.Designer.cs new file mode 100644 index 0000000..b4bce1e --- /dev/null +++ b/HRM_MQ_Consumer_Service/HRMConsumerService.Designer.cs @@ -0,0 +1,37 @@ +namespace HRM_MQ_Consumer_Service +{ + partial class HRMConsumerService + { + /// + /// Обязательная переменная конструктора. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Освободить все используемые ресурсы. + /// + /// истинно, если управляемый ресурс должен быть удален; иначе ложно. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Код, автоматически созданный конструктором компонентов + + /// + /// Требуемый метод для поддержки конструктора — не изменяйте + /// содержимое этого метода с помощью редактора кода. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + this.ServiceName = "Service1"; + } + + #endregion + } +} diff --git a/HRM_MQ_Consumer_Service/HRMConsumerService.cs b/HRM_MQ_Consumer_Service/HRMConsumerService.cs new file mode 100644 index 0000000..260d98b --- /dev/null +++ b/HRM_MQ_Consumer_Service/HRMConsumerService.cs @@ -0,0 +1,77 @@ +using HRM_MQ_Consumer_Service.Parsers; +using Microsoft.Extensions.Configuration; +using RabbitMQ.Client; +using RabbitMQ.Client.Events; +using Simple.OData.Client; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Configuration; +using System.Data; +using System.Diagnostics; +using System.Linq; +using System.ServiceProcess; +using System.Text; +using System.Threading.Tasks; + +namespace HRM_MQ_Consumer_Service +{ + public partial class HRMConsumerService : ServiceBase + { + private ConnectionFactory connectionFactory = new ConnectionFactory + { + HostName = ConfigurationManager.AppSettings["rabbitmq_host_name"], + UserName = ConfigurationManager.AppSettings["rabbitmq_user_name"], + Password = ConfigurationManager.AppSettings["rabbitmq_password"], + VirtualHost = ConfigurationManager.AppSettings["rabbitmq_virtualhost"] + }; + private IConnection _connection; + private IChannel _channel; + private AsyncEventingBasicConsumer _consumer; + private CounterpartyJSONParser _counterpartyParser; + public HRMConsumerService() + { + InitializeComponent(); + } + + internal void TestStatupAndStop(string[] args) + { + this.OnStart(args); + Console.ReadLine(); + this.OnStop(); + } + + protected override async void OnStart(string[] args) + { + string queue = ConfigurationManager.AppSettings["rabbitmq_queue_name"]; + _connection = await connectionFactory.CreateConnectionAsync(); + _channel = await _connection.CreateChannelAsync(); + await _channel.QueueDeclareAsync( + queue: queue, + durable: false, + exclusive: false, + autoDelete: false, + arguments: null); + _consumer = new AsyncEventingBasicConsumer(_channel); + _counterpartyParser = new CounterpartyJSONParser(); + _consumer.ReceivedAsync += async (model, ea) => + { + var body = ea.Body.ToArray(); + var message = Encoding.UTF8.GetString(body); + var result = await _counterpartyParser.Parse(message); + //var result = await _counterpartyParser.Parse(message); + //Console.WriteLine($"Recieved {message}"); + }; + await _channel.BasicConsumeAsync( + queue: queue, + autoAck: true, + consumer: _consumer); + } + + protected override void OnStop() + { + _channel?.Dispose(); + _connection?.Dispose(); + } + } +} diff --git a/HRM_MQ_Consumer_Service/HRM_MQ_Consumer_Service.csproj b/HRM_MQ_Consumer_Service/HRM_MQ_Consumer_Service.csproj new file mode 100644 index 0000000..045722f --- /dev/null +++ b/HRM_MQ_Consumer_Service/HRM_MQ_Consumer_Service.csproj @@ -0,0 +1,159 @@ + + + + + Debug + AnyCPU + {4E5D446E-7AF9-490D-B503-59BCBFCCA63F} + Exe + HRM_MQ_Consumer_Service + HRM_MQ_Consumer_Service + v4.8 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + ..\packages\Microsoft.Extensions.Configuration.Abstractions.9.0.6\lib\net462\Microsoft.Extensions.Configuration.Abstractions.dll + + + ..\packages\Microsoft.Extensions.ObjectPool.8.0.4\lib\net462\Microsoft.Extensions.ObjectPool.dll + + + ..\packages\Microsoft.Extensions.Primitives.9.0.6\lib\net462\Microsoft.Extensions.Primitives.dll + + + ..\packages\Microsoft.OData.Core.7.21.0\lib\net45\Microsoft.OData.Core.dll + + + ..\packages\Microsoft.OData.Edm.7.21.0\lib\net45\Microsoft.OData.Edm.dll + + + ..\packages\Microsoft.Spatial.7.21.0\lib\net45\Microsoft.Spatial.dll + + + ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + ..\packages\RabbitMQ.Client.7.1.2\lib\netstandard2.0\RabbitMQ.Client.dll + + + ..\packages\Simple.OData.V4.Client.6.0.1\lib\net461\Simple.OData.Client.Core.dll + + + ..\packages\Simple.OData.V4.Client.6.0.1\lib\net461\Simple.OData.Client.Dynamic.dll + + + ..\packages\Simple.OData.V4.Client.6.0.1\lib\net461\Simple.OData.Client.V4.Adapter.dll + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + + + + ..\packages\System.Diagnostics.DiagnosticSource.8.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.IO.Pipelines.8.0.0\lib\net462\System.IO.Pipelines.dll + + + + ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Text.Encodings.Web.4.7.2\lib\net461\System.Text.Encodings.Web.dll + + + ..\packages\System.Text.Json.4.6.0\lib\net461\System.Text.Json.dll + + + ..\packages\System.Threading.Channels.8.0.0\lib\net462\System.Threading.Channels.dll + + + ..\packages\System.Threading.RateLimiting.8.0.0\lib\net462\System.Threading.RateLimiting.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + + + + + + + + + + + + + + + + + + + + Component + + + ProjectInstaller.cs + + + Component + + + HRMConsumerService.cs + + + + + + + + + + + ProjectInstaller.cs + + + + \ No newline at end of file diff --git a/HRM_MQ_Consumer_Service/Logger/Logger.cs b/HRM_MQ_Consumer_Service/Logger/Logger.cs new file mode 100644 index 0000000..3b75102 --- /dev/null +++ b/HRM_MQ_Consumer_Service/Logger/Logger.cs @@ -0,0 +1,127 @@ +using System; +using System.IO; +using System.Text; + +namespace HRM_MQ_Consumer_Service.Logger +{ + public enum LogLevel + { + Info, + Warning, + Error + } + + public class Logger + { + //private readonly string _name; + //private readonly string _logDirPath; + + public Logger(string name, string logDirPath = "log\\") + { + _name = name; + _directoryPath = logDirPath; + + if (!Directory.Exists(logDirPath)) + { + Directory.CreateDirectory(logDirPath); + } + // Ensure the log file exists or create it + //if (!File.Exists(_logFilePath)) + //{ + // using (File.Create(_logFilePath)) { } + //} + } + + private string _name; + + public string Name + { + get { return _name; } + set { _name = value; } + } + + + private string _directoryPath; + + public string DirectoryPath + { + get { return _directoryPath; } + set { _directoryPath = value; } + } + + public void Log(LogLevel level, string message) + { + var bytes = Encoding.UTF8.GetBytes(message); + var str = Encoding.UTF8.GetString(bytes); + var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + var logMessage = $"[{timestamp}] [{level}] [{_name}] {str}"; + + // Write to console (optional) + WriteToConsole(level, logMessage); + + // Write to file + WriteToFile(logMessage); + } + + private void WriteToConsole(LogLevel level, string message) + { + switch (level) + { + case LogLevel.Info: + Console.ForegroundColor = ConsoleColor.Green; + break; + case LogLevel.Warning: + Console.ForegroundColor = ConsoleColor.Yellow; + break; + case LogLevel.Error: + Console.ForegroundColor = ConsoleColor.Red; + break; + default: + Console.ResetColor(); + break; + } + + Console.WriteLine(message); + Console.ResetColor(); + } + + private void WriteToFile(string message) + { + var today = DateTime.Now.ToString("yyyy-MM-dd"); + var filePath = $"{_directoryPath}\\{today}_{_name}.txt"; + if (!File.Exists(filePath)) + { + using (File.Create(filePath)) { } + } + try + { + // Append the log message to the file + using (StreamWriter writer = new StreamWriter(filePath, true, Encoding.UTF8)) + { + writer.WriteLine(message); + } + } + catch (Exception ex) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"Failed to write to log file: {ex.Message}"); + Console.ResetColor(); + } + } + + public void Info(string message) + { + Log(LogLevel.Info, message); + } + + public void Warn(string message) + { + Log(LogLevel.Warning, message); + } + + public void Error(string message) + { + Log(LogLevel.Error, message); + } + } +} diff --git a/HRM_MQ_Consumer_Service/OData/ODataAccess.cs b/HRM_MQ_Consumer_Service/OData/ODataAccess.cs new file mode 100644 index 0000000..c12e1e7 --- /dev/null +++ b/HRM_MQ_Consumer_Service/OData/ODataAccess.cs @@ -0,0 +1,41 @@ +using Simple.OData.Client; +using System.Text; +using System.Configuration; +using Microsoft.Extensions.Configuration; +using System.Net.Http; +using System; +using System.Collections.Generic; + +namespace HRM_MQ_Consumer_Service.OData +{ + public class ODataAccess + { + // URL сервиса интеграции. + + private string IntegrationServiceUrl; + private string Login; + private string Password; + + //private const string IntegrationServiceUrl = "https://qdoc.solidcore-resources.com/Integration/odata/"; + //private const string Login = "Administrator"; + //private const string Password = "MQVuEw9avO"; + + public ODataAccess() + { + IntegrationServiceUrl = ConfigurationManager.AppSettings["qdoc_integration_service_url"]; + Login = ConfigurationManager.AppSettings["qdoc_login"]; + Password = ConfigurationManager.AppSettings["qdoc_password"]; + // Настройки Simple OData Client: добавление ко всем запросам URL сервиса и + // заголовка с данными аутентификации. + var odataClientSettings = new ODataClientSettings(new Uri(IntegrationServiceUrl)); + odataClientSettings.BeforeRequest += (HttpRequestMessage message) => + { + var authenticationHeaderValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{Login}:{Password}")); + message.Headers.Add("Authorization", "Basic " + authenticationHeaderValue); + }; + Client = new ODataClient(odataClientSettings); + } + + public ODataClient Client { get; set; } + } +} diff --git a/HRM_MQ_Consumer_Service/OData/QDocWrapper.cs b/HRM_MQ_Consumer_Service/OData/QDocWrapper.cs new file mode 100644 index 0000000..f868e7a --- /dev/null +++ b/HRM_MQ_Consumer_Service/OData/QDocWrapper.cs @@ -0,0 +1,184 @@ +using HRM_MQ_Consumer_Service.Structure; +using Simple.OData.Client; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Threading.Tasks; + +namespace HRM_MQ_Consumer_Service.OData +{ + public class QDocWrapper + { + private ODataClient _client; + private Logger.Logger _logger; + + public QDocWrapper(Logger.Logger logger) + { + var oDataAccess = new ODataAccess(); + _client = oDataAccess.Client; + _logger = logger; + } + + public async Task GetCompanyByBIN(string bin) + { + if (!string.IsNullOrEmpty(bin)) + { + var company = await _client + .For("ICompanies") + .Expand("HeadCompany") + .Filter($"BINArmadoc eq '{bin}'") + .FindEntryAsync(); + if (company != null) + { + var result = new CounterParty + { + Id = (long)company["Id"], + Name = company["Name"]?.ToString(), + LegalAddress = company["LegalAddress"]?.ToString(), + PostalAddress = company["PostalAddress"]?.ToString(), + GeneralCompany = company["HeadCompany"]?.ToString(), + Code = company["Code"]?.ToString(), + Guid = company["ExternalId"]?.ToString(), + Resident = !(bool)company["Nonresident"], + LegalName = company["LegalName"]?.ToString(), + Bin = company["BINArmadoc"]?.ToString() + }; + return result; + } + } + return null; + } + + public async Task GetCompanyByGuid(string guid) + { + if (!string.IsNullOrEmpty(guid)) + { + var company = await _client + .For("ICompanies") + .Expand("HeadCompany") + .Filter($"ExternalId eq '{guid}'") + .FindEntryAsync(); + if (company != null) + { + var result = new CounterParty + { + Id = (long)company["Id"], + Name = company["Name"]?.ToString(), + LegalAddress = company["LegalAddress"]?.ToString(), + PostalAddress = company["PostalAddress"]?.ToString(), + GeneralCompany = company["HeadCompany"]?.ToString(), + Code = company["Code"]?.ToString(), + Guid = company["ExternalId"]?.ToString(), + Resident = !(bool)company["Nonresident"], + LegalName = company["LegalName"]?.ToString(), + Bin = company["BINArmadoc"]?.ToString() + }; + return result; + } + } + return null; + } + + public async Task GetBusinessUnitByBin(string bin) + { + bool result = false; + if (!string.IsNullOrEmpty(bin)) + { + var businessUnit = await _client + .For("ICompanies") + .Expand("HeadCompany") + .Filter($"ExternalId eq '{bin}'") + .FindEntryAsync(); + if (businessUnit != null) result = true; + } + return result; + } + + public async Task UpdateCounterparty(CounterParty counterparty) + { + try + { + if (counterparty == null) return; + var newCounterparty = new + { + counterparty.Name, + counterparty.LegalName, + ExternalId = counterparty.Guid, + Status = counterparty.Deleted == "true" ? "Closed" : "Active", + counterparty.LegalAddress, + counterparty.PostalAddress, + Nonresident = counterparty.Resident != true ? true : false, + BINArmadoc = counterparty.Bin != null ? counterparty.Bin : string.Empty, + TIN = counterparty.Tin != null ? counterparty.Tin : string.Empty + }; + await _client + .For("ICompanies") + .Key(counterparty.UpdCounterparty.Id) + .Set(newCounterparty) + .UpdateEntryAsync(); + _logger.Info($"{counterparty.Name} updated."); + } + catch (Exception ex) + { + _logger.Error($"{counterparty.Name} - {ex.Message}"); + } + } + + internal async Task CreateCounterparty(CounterParty counterparty) + { + try + { + if (counterparty == null) return; + var newCounterparty = new + { + counterparty.Name, + counterparty.LegalName, + ExternalId = counterparty.Guid, + Status = counterparty.Deleted == "true" ? "Active" : "Closed", + counterparty.LegalAddress, + counterparty.PostalAddress, + Nonresident = counterparty.Resident != true ? true : false, + BINArmadoc = counterparty.Resident == true ? counterparty.Bin : string.Empty, + TIN = counterparty.Resident == false ? counterparty.Bin : string.Empty + }; + await _client + .For("ICompanies") + .Set(newCounterparty) + .InsertEntryAsync(); + _logger.Info($"{counterparty.Name} created."); + } + catch (Exception ex) + { + _logger.Error($"{counterparty.Name} - {ex.Message}"); + } + } + + internal async Task CreateCounterparty(CounterParty1C counterparty) + { + try + { + if (counterparty == null) return; + var newCounterparty = new + { + counterparty.Name, + counterparty.LegalName, + ExternalId = counterparty.Guid, + Nonresident = counterparty.NonResident, + BINArmadoc = counterparty.NonResident != true ? counterparty.BIN : string.Empty, + TIN = counterparty.NonResident != false ? counterparty.BIN : string.Empty + }; + await _client + .For("ICompanies") + .Set(newCounterparty) + .InsertEntryAsync(); + _logger.Info($"{counterparty.Name} created."); + } + catch (Exception ex) + { + _logger.Error($"{counterparty.Name} - {ex.Message}"); + } + } + } +} diff --git a/HRM_MQ_Consumer_Service/Parsers/CounterpartyJSONParser.cs b/HRM_MQ_Consumer_Service/Parsers/CounterpartyJSONParser.cs new file mode 100644 index 0000000..89e9802 --- /dev/null +++ b/HRM_MQ_Consumer_Service/Parsers/CounterpartyJSONParser.cs @@ -0,0 +1,54 @@ +using HRM_MQ_Consumer_Service.OData; +using HRM_MQ_Consumer_Service.Structure; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HRM_MQ_Consumer_Service.Parsers +{ + internal class CounterpartyJSONParser + { + private Logger.Logger _logger; + private static QDocWrapper _wrapper; + + public CounterpartyJSONParser() + { + _logger = new Logger.Logger("Counterparties_test"); + _wrapper = new QDocWrapper(_logger); + } + + public async Task Parse(string message) + { + bool result = false; + CounterParty company; + var converted = JsonConvert.DeserializeObject(message); + var found = await TryFindCompany(converted); + if (found != null) + { + await _wrapper.UpdateCounterparty(found); + } + else await _wrapper.CreateCounterparty(converted); + return result; + } + + private async Task TryFindCompany(CounterParty1C converted) + { + CounterParty company; + + company = await _wrapper.GetCompanyByGuid(converted.Guid); + + if (company == null) + { + company = await _wrapper.GetCompanyByBIN(converted.BIN); + } + if (company != null) + { + company.UpdCounterparty = new CounterParty { Id = company.Id }; + } + return company; + } + } +} diff --git a/HRM_MQ_Consumer_Service/Parsers/CounterpartyXMLParser.cs b/HRM_MQ_Consumer_Service/Parsers/CounterpartyXMLParser.cs new file mode 100644 index 0000000..8bce871 --- /dev/null +++ b/HRM_MQ_Consumer_Service/Parsers/CounterpartyXMLParser.cs @@ -0,0 +1,169 @@ +using HRM_MQ_Consumer_Service.OData; +using System; +using System.Threading.Tasks; +using System.Xml; + +namespace HRM_MQ_Consumer_Service.Parsers +{ + internal class CounterpartyXMLParser + { + private Logger.Logger _logger; + private static QDocWrapper _wrapper; + + public CounterpartyXMLParser() + { + _logger = new Logger.Logger("Counterparties_test"); + _wrapper = new QDocWrapper(_logger); + } + public async Task Parse(string message) + { + var package = new PackageInfo(); + var xml = new XmlDocument(); + xml.LoadXml(message); + XmlElement xRoot = xml.DocumentElement; + XmlNodeList nodes = xRoot.SelectNodes("*"); + package = GetPackageInfo(nodes, package); + + foreach (var counterparty in package.AllLoadedComp) + { + if (counterparty.UpdCounterparty != null) + { + await _wrapper.UpdateCounterparty(counterparty); + } + else + { + await _wrapper.CreateCounterparty(counterparty); + } + } + + _logger.Info("Package loading complete."); + return true; + } + + private static PackageInfo GetPackageInfo(XmlNodeList nodeList, PackageInfo packageInfo) + { + foreach (XmlNode node in nodeList) + { + packageInfo = RecurseXmlDocumentNoSiblings(node, packageInfo); + } + return packageInfo; + } + + private static PackageInfo RecurseXmlDocumentNoSiblings(XmlNode root, PackageInfo packageInfo) + { + if (root is XmlElement) + { + if (root.HasChildNodes) + return RecurseXmlDocument(root.FirstChild, packageInfo).Result; + } + return packageInfo; + } + + private static async Task RecurseXmlDocument(XmlNode root, PackageInfo packageInfo) + { + if (root is XmlElement) + { + if (root.Name == "m:Дата") + // Dialogs.NotifyMessage("Дата отправки пакета " + root.InnerText); + packageInfo.DateReceived = DateTime.Parse(root.InnerText); + if (root.Name == "m:Номер") + // Dialogs.NotifyMessage("Номер пакета " + root.InnerText); + packageInfo.Id = root.InnerText; + if (root.Name == "m:Объекты") + { + + XmlNodeList allObjLoad = root.ChildNodes; + if (allObjLoad.Count > 0) + { + //"Осуществляется загрузка контрагентов со следующими параметрами:" + + foreach (XmlNode item in allObjLoad) + { + CounterParty tempCompany = null; + tempCompany = new CounterParty(); + foreach (XmlNode Countparty in item.ChildNodes) + { + if (Countparty.Name == "m:Тип" && Countparty.InnerText != "Справочник.Контрагенты") + { + //$"Это не контрагент, тип {Countparty.InnerText}" + packageInfo.ErrorsList.Add($"Это не контрагент, тип {Countparty.InnerText}"); + continue; + } + + if (Countparty.Name == "m:Реквизиты") + { + foreach (XmlNode CountpartyOthers in Countparty.ChildNodes) + { + string tempKey = CountpartyOthers.ChildNodes[0].InnerText; + string tempValue = CountpartyOthers.ChildNodes[1].Name == "m:ЗначениеСсылка" ? CountpartyOthers.ChildNodes[1].ChildNodes[1].InnerText : CountpartyOthers.ChildNodes[1].InnerText; + + switch (tempKey) + { + case "Наименование": + tempCompany.Name = tempValue; + break; + case "ГоловнойКонтрагент": + tempCompany.GeneralCompany = tempValue; + break; + case "НаименованиеПолное": + tempCompany.LegalName = tempValue; + break; + case "Код": + tempCompany.Code = tempValue; + break; + case "БИН": + tempCompany.Bin = tempValue; + break; + case "ЮрАдрес": + tempCompany.LegalAddress = tempValue; + break; + case "ФактАдрес": + tempCompany.PostalAddress = tempValue; + break; + case "Резидент": + tempCompany.Resident = bool.Parse(tempValue); + break; + default: + break; + } + } + } + + if (!string.IsNullOrEmpty(tempCompany.Bin)) + { + tempCompany.UpdCounterparty = _wrapper.GetCompanyByBIN(tempCompany.Bin).Result; + } + else + { + tempCompany.UpdCounterparty = _wrapper.GetCompanyByGuid(tempCompany.Guid).Result; + } + + if (Countparty.Name == "m:Ид") + { + tempCompany.UpdCounterparty = _wrapper.GetCompanyByGuid(Countparty.InnerText).Result; + tempCompany.Guid = Countparty.InnerText; + } + if (Countparty.Name == "m:ПометкаУдаления") + tempCompany.Deleted = Countparty.InnerText; + } + //if (armad.ExchangeKZ.BusinessUnits.GetAll().FirstOrDefault(x => x.BINArmadoc == tempCompany.Bin) != null) + if (_wrapper.GetBusinessUnitByBin(tempCompany.Bin).Result) + { + continue; + } + packageInfo.AllLoadedComp.Add(tempCompany); + + } + } + return packageInfo; + } + if (root.HasChildNodes) + packageInfo = RecurseXmlDocument(root.FirstChild, packageInfo).Result; + if (root.NextSibling != null) + packageInfo = RecurseXmlDocument(root.NextSibling, packageInfo).Result; + + } + return packageInfo; + } + } +} \ No newline at end of file diff --git a/HRM_MQ_Consumer_Service/Program.cs b/HRM_MQ_Consumer_Service/Program.cs new file mode 100644 index 0000000..2056460 --- /dev/null +++ b/HRM_MQ_Consumer_Service/Program.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceProcess; +using System.Text; +using System.Threading.Tasks; + +namespace HRM_MQ_Consumer_Service +{ + internal static class Program + { + /// + /// Главная точка входа для приложения. + /// + static void Main(string[] args) + { + //Для отладки сервиса + if (Environment.UserInteractive) + { + HRMConsumerService service = new HRMConsumerService(); + service.TestStatupAndStop(args); + } + else + { + ServiceBase[] ServicesToRun; + ServicesToRun = new ServiceBase[] + { + new HRMConsumerService() + }; + ServiceBase.Run(ServicesToRun); + } + } + } +} diff --git a/HRM_MQ_Consumer_Service/ProjectInstaller.Designer.cs b/HRM_MQ_Consumer_Service/ProjectInstaller.Designer.cs new file mode 100644 index 0000000..a5e2991 --- /dev/null +++ b/HRM_MQ_Consumer_Service/ProjectInstaller.Designer.cs @@ -0,0 +1,60 @@ +namespace HRM_MQ_Consumer_Service +{ + partial class ProjectInstaller + { + /// + /// Обязательная переменная конструктора. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Освободить все используемые ресурсы. + /// + /// истинно, если управляемый ресурс должен быть удален; иначе ложно. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Код, автоматически созданный конструктором компонентов + + /// + /// Требуемый метод для поддержки конструктора — не изменяйте + /// содержимое этого метода с помощью редактора кода. + /// + private void InitializeComponent() + { + this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller(); + this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller(); + // + // serviceProcessInstaller1 + // + this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalService; + this.serviceProcessInstaller1.Password = null; + this.serviceProcessInstaller1.Username = null; + // + // serviceInstaller1 + // + this.serviceInstaller1.Description = "Message queue consumer"; + this.serviceInstaller1.DisplayName = "1C HRM RabbitMQ Consumer"; + this.serviceInstaller1.ServiceName = "1C HRM RabbitMQ Consumer"; + this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic; + // + // ProjectInstaller + // + this.Installers.AddRange(new System.Configuration.Install.Installer[] { + this.serviceProcessInstaller1, + this.serviceInstaller1}); + + } + + #endregion + + private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1; + private System.ServiceProcess.ServiceInstaller serviceInstaller1; + } +} \ No newline at end of file diff --git a/HRM_MQ_Consumer_Service/ProjectInstaller.cs b/HRM_MQ_Consumer_Service/ProjectInstaller.cs new file mode 100644 index 0000000..6c37855 --- /dev/null +++ b/HRM_MQ_Consumer_Service/ProjectInstaller.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Configuration.Install; +using System.Linq; +using System.Threading.Tasks; + +namespace HRM_MQ_Consumer_Service +{ + [RunInstaller(true)] + public partial class ProjectInstaller : System.Configuration.Install.Installer + { + public ProjectInstaller() + { + InitializeComponent(); + } + } +} diff --git a/HRM_MQ_Consumer_Service/ProjectInstaller.resx b/HRM_MQ_Consumer_Service/ProjectInstaller.resx new file mode 100644 index 0000000..1a93e3b --- /dev/null +++ b/HRM_MQ_Consumer_Service/ProjectInstaller.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 54 + + + 221, 53 + + + False + + \ No newline at end of file diff --git a/HRM_MQ_Consumer_Service/Properties/AssemblyInfo.cs b/HRM_MQ_Consumer_Service/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7074ca9 --- /dev/null +++ b/HRM_MQ_Consumer_Service/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Общие сведения об этой сборке предоставляются следующим набором +// набора атрибутов. Измените значения этих атрибутов, чтобы изменить сведения, +// общие сведения об этой сборке. +[assembly: AssemblyTitle("HRM_MQ_Consumer_Service")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("HRM_MQ_Consumer_Service")] +[assembly: AssemblyCopyright("Copyright © 2025")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми +// для компонентов COM. Если необходимо обратиться к типу в этой сборке через +// компонент COM, задайте для атрибута ComVisible этого типа значение TRUE. +[assembly: ComVisible(false)] + +// Указанный ниже идентификатор GUID предназначен для идентификации библиотеки типов, если этот проект будет видимым для COM-объектов +[assembly: Guid("4e5d446e-7af9-490d-b503-59bcbfcca63f")] + +// Сведения о версии сборки состоят из указанных ниже четырех значений: +// +// Основной номер версии +// Дополнительный номер версии +// Номер сборки +// Номер редакции +// +// Можно задать все значения или принять номера сборки и редакции по умолчанию +// используя "*", как показано ниже: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/HRM_MQ_Consumer_Service/Structure/CounterParty.cs b/HRM_MQ_Consumer_Service/Structure/CounterParty.cs new file mode 100644 index 0000000..7992e6b --- /dev/null +++ b/HRM_MQ_Consumer_Service/Structure/CounterParty.cs @@ -0,0 +1,42 @@ +using Newtonsoft.Json; +using System; + +namespace HRM_MQ_Consumer_Service +{ + public class CounterParty + { + public long Id { get; set; } + //Наименование + [JsonProperty("Наименование")] + public string Name { get; set; } + //Юридическое наименование + [JsonProperty("ПолноеНаименование")] + public string LegalName { get; set; } + //Идентификатор 1С + [JsonProperty("УникальныйИдентификатор")] + public string Guid { get; set; } + //Головная организация + public string GeneralCompany { get; set; } + //Код + public string Code { get; set; } + //БИН + [JsonProperty("БИН")] + public string Bin { get; set; } + //ИНН + [JsonProperty("ИНН")] + public string Tin { get; set; } + //Юридический адрес + public string LegalAddress { get; set; } + //Почтовый адрес + public string PostalAddress { get; set; } + //Резидент + [JsonProperty("НеРезидент")] + public bool Resident { get; set; } + //Признак удаления + public string Deleted { get; set; } + + //Найденный объект + public CounterParty UpdCounterparty { get; set; } + + } +} \ No newline at end of file diff --git a/HRM_MQ_Consumer_Service/Structure/CounterParty1C.cs b/HRM_MQ_Consumer_Service/Structure/CounterParty1C.cs new file mode 100644 index 0000000..f1378db --- /dev/null +++ b/HRM_MQ_Consumer_Service/Structure/CounterParty1C.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HRM_MQ_Consumer_Service.Structure +{ + public class CounterParty1C + { + [JsonProperty("Наименование")] + public string Name { get; set; } + [JsonProperty("БИН")] + public string BIN { get; set; } + [JsonProperty("УникальныйИдентификатор")] + public string Guid { get; set; } + [JsonProperty("НеРезидент")] + public bool NonResident { get; set; } + [JsonProperty("ПолноеНаименование")] + public string LegalName { get; set; } + [JsonProperty("ИНН")] + public string TIN { get; set; } + } +} diff --git a/HRM_MQ_Consumer_Service/Structure/PackageInfo.cs b/HRM_MQ_Consumer_Service/Structure/PackageInfo.cs new file mode 100644 index 0000000..5ee2071 --- /dev/null +++ b/HRM_MQ_Consumer_Service/Structure/PackageInfo.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; + +namespace HRM_MQ_Consumer_Service +{ + partial class PackageInfo + { + //Номер пакета + public string Id { get; set; } + //Строка авторизации + public string Auth { get; set; } + //Тело запроса + public string RequestUrl { get; set; } + //Тело ответа + public string RequestXml { get; set; } + //Тело запроса + public string ResponseXml { get; set; } + //Список ошибок + public List ErrorsList { get; set; } + //Дата Ответа + public DateTime DateReceived { get; set; } + //Запись в логе + //public ILogsExchange log { get; set; } + //структура запроса + public bool OperationCheck { get; set; } + //вызов delete запроса + public bool Delete { get; set; } + + //Перечисление данных для создания/обновления контрагентов + public List AllLoadedComp { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/HRM_MQ_Consumer_Service/packages.config b/HRM_MQ_Consumer_Service/packages.config new file mode 100644 index 0000000..c6302df --- /dev/null +++ b/HRM_MQ_Consumer_Service/packages.config @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file