using System; using System.Collections.Generic; using System.Data.SQLite; namespace Электронная_Фармация.Classes { /// /// Аптека = грузополучатель + LocationId. Прайс общий, заказы уходят с location_id выбранной аптеки. /// public static class ConsigneeHelper { public static string GetDefaultConsigneeName() { try { using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString)) { connection.Open(); using (var command = new SQLiteCommand( @"SELECT ConsigneesName FROM Consignees ORDER BY ConsigneesUseAsDefault DESC, ConsigneesName LIMIT 1", connection)) { var result = command.ExecuteScalar(); return result == null || result == DBNull.Value ? string.Empty : result.ToString().Trim(); } } } catch { return string.Empty; } } public static string GetLocationIdByName(string consigneeName) { if (string.IsNullOrWhiteSpace(consigneeName)) { return string.Empty; } using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString)) { connection.Open(); using (var command = new SQLiteCommand( @"SELECT ifnull(LocationId, '') FROM Consignees WHERE ConsigneesName = @name LIMIT 1", connection)) { command.Parameters.AddWithValue("@name", consigneeName.Trim()); var result = command.ExecuteScalar(); return result == null || result == DBNull.Value ? string.Empty : result.ToString().Trim(); } } } public static string ResolveLocationId(string consigneeName) { var fromConsignee = GetLocationIdByName(consigneeName); if (!string.IsNullOrWhiteSpace(fromConsignee)) { return fromConsignee; } return AppConfig.LocationId ?? string.Empty; } /// /// Помечает аптеку активной и синхронизирует AppConfig.LocationId. /// public static void SetActiveConsignee(string consigneeName) { if (string.IsNullOrWhiteSpace(consigneeName)) { return; } var name = consigneeName.Trim(); using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString)) { connection.Open(); using (var tx = connection.BeginTransaction()) { using (var clear = new SQLiteCommand( "UPDATE Consignees SET ConsigneesUseAsDefault = 0", connection, tx)) { clear.ExecuteNonQuery(); } using (var setDefault = new SQLiteCommand( @"UPDATE Consignees SET ConsigneesUseAsDefault = 1 WHERE ConsigneesName = @name", connection, tx)) { setDefault.Parameters.AddWithValue("@name", name); setDefault.ExecuteNonQuery(); } tx.Commit(); } var locationId = GetLocationIdByName(name); if (!string.IsNullOrWhiteSpace(locationId)) { AppConfig.SetLocationId(locationId); } } } public static void SetLocationId(string consigneeName, string locationId) { if (string.IsNullOrWhiteSpace(consigneeName)) { return; } using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString)) { connection.Open(); using (var command = new SQLiteCommand( @"UPDATE Consignees SET LocationId = @loc WHERE ConsigneesName = @name", connection)) { command.Parameters.AddWithValue("@loc", (locationId ?? string.Empty).Trim()); command.Parameters.AddWithValue("@name", consigneeName.Trim()); command.ExecuteNonQuery(); } } } public static void MigrateGlobalLocationIdIfNeeded(SQLiteConnection connection) { var global = AppConfig.LocationId; if (string.IsNullOrWhiteSpace(global)) { return; } using (var command = new SQLiteCommand( @"UPDATE Consignees SET LocationId = @loc WHERE (LocationId IS NULL OR trim(LocationId) = '') AND ( ConsigneesUseAsDefault = 1 OR (SELECT COUNT(*) FROM Consignees) = 1 )", connection)) { command.Parameters.AddWithValue("@loc", global.Trim()); command.ExecuteNonQuery(); } } public static void ApplyLocationIdToEmptyConsignees(string locationId) { if (string.IsNullOrWhiteSpace(locationId)) { return; } using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString)) { connection.Open(); using (var command = new SQLiteCommand( @"UPDATE Consignees SET LocationId = @loc WHERE LocationId IS NULL OR trim(LocationId) = ''", connection)) { command.Parameters.AddWithValue("@loc", locationId.Trim()); command.ExecuteNonQuery(); } } } public static IList GetKnownSupplierIds() { var result = new List(); using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString)) { connection.Open(); using (var command = new SQLiteCommand( @"SELECT DISTINCT trim(supplier_id) FROM PriceList WHERE supplier_id IS NOT NULL AND trim(supplier_id) <> '' ORDER BY 1", connection)) using (var reader = command.ExecuteReader()) { while (reader.Read()) { var id = reader.GetString(0); if (!string.IsNullOrWhiteSpace(id)) { result.Add(id); } } } } return result; } /// /// Процент наценки, который клиент задал вручную для аптеки. /// null = ещё не сохраняли, брать fallback. /// public static decimal? GetClientMarkupPercent(string consigneeName) { if (string.IsNullOrWhiteSpace(consigneeName)) { return null; } try { using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString)) { connection.Open(); using (var command = new SQLiteCommand( @"SELECT ClientMarkupPercent FROM Consignees WHERE ConsigneesName = @name LIMIT 1", connection)) { command.Parameters.AddWithValue("@name", consigneeName.Trim()); var result = command.ExecuteScalar(); if (result == null || result == DBNull.Value) { return null; } if (result is decimal d) { return d; } if (decimal.TryParse( Convert.ToString(result, System.Globalization.CultureInfo.InvariantCulture), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out var parsed)) { return parsed; } return null; } } } catch { return null; } } /// /// Сохраняет процент наценки клиента для конкретной аптеки. /// Не сбрасывается при обновлении прайса. /// public static void SetClientMarkupPercent(string consigneeName, decimal markupPercent) { if (string.IsNullOrWhiteSpace(consigneeName)) { return; } using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString)) { connection.Open(); using (var command = new SQLiteCommand( @"UPDATE Consignees SET ClientMarkupPercent = @pct WHERE ConsigneesName = @name", connection)) { command.Parameters.AddWithValue("@pct", markupPercent); command.Parameters.AddWithValue("@name", consigneeName.Trim()); command.ExecuteNonQuery(); } } } /// /// Если у аптеки ещё нет сохранённого процента — записать стартовое значение с сервера. /// Уже введённые клиентом значения не трогаем. /// public static void SeedClientMarkupPercentIfEmpty(decimal? serverMarkupPercent) { if (!serverMarkupPercent.HasValue) { return; } using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString)) { connection.Open(); using (var command = new SQLiteCommand( @"UPDATE Consignees SET ClientMarkupPercent = @pct WHERE ClientMarkupPercent IS NULL", connection)) { command.Parameters.AddWithValue("@pct", serverMarkupPercent.Value); command.ExecuteNonQuery(); } } } /// /// Подтягивает грузополучателей с сервера (BuyerLocation) в локальную таблицу Consignees. /// Источник истины — веб-кабинет; локально только кэш + выбор активной аптеки. /// public static int SyncFromServer(IList locations) { if (locations == null || locations.Count == 0) { return 0; } var upserted = 0; using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString)) { connection.Open(); using (var tx = connection.BeginTransaction()) { // Сбрасываем default — выставим по данным сервера. using (var clearDefault = new SQLiteCommand( "UPDATE Consignees SET ConsigneesUseAsDefault = 0", connection, tx)) { clearDefault.ExecuteNonQuery(); } int nextCode; using (var nextCodeCmd = new SQLiteCommand( "SELECT ifnull(MAX(codeConsignees), 0) + 1 FROM Consignees", connection, tx)) { nextCode = Convert.ToInt32(nextCodeCmd.ExecuteScalar()); } foreach (var loc in locations) { var locationId = (loc.BuyerLocationID ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(locationId)) { continue; } var address = (loc.Address ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(address)) { address = "Грузополучатель"; } var name = address; if (name.Length > 120) { name = name.Substring(0, 120); } long? existingId = null; using (var find = new SQLiteCommand( @"SELECT idConsignees FROM Consignees WHERE lower(trim(LocationId)) = lower(@loc) LIMIT 1", connection, tx)) { find.Parameters.AddWithValue("@loc", locationId); var found = find.ExecuteScalar(); if (found != null && found != DBNull.Value) { existingId = Convert.ToInt64(found); } } if (existingId.HasValue) { using (var upd = new SQLiteCommand( @"UPDATE Consignees SET ConsigneesName = @name, ConsigneesAddress = @address, ConsigneesUseAsDefault = @isDefault, LocationId = @loc WHERE idConsignees = @id", connection, tx)) { upd.Parameters.AddWithValue("@name", name); upd.Parameters.AddWithValue("@address", address); upd.Parameters.AddWithValue("@isDefault", loc.IsDefault ? 1 : 0); upd.Parameters.AddWithValue("@loc", locationId); upd.Parameters.AddWithValue("@id", existingId.Value); upd.ExecuteNonQuery(); } } else { using (var ins = new SQLiteCommand( @"INSERT INTO Consignees (codeConsignees, ConsigneesName, ConsigneesAddress, ConsigneesUseAsDefault, LocationId) VALUES (@code, @name, @address, @isDefault, @loc)", connection, tx)) { ins.Parameters.AddWithValue("@code", nextCode++); ins.Parameters.AddWithValue("@name", name); ins.Parameters.AddWithValue("@address", address); ins.Parameters.AddWithValue("@isDefault", loc.IsDefault ? 1 : 0); ins.Parameters.AddWithValue("@loc", locationId); ins.ExecuteNonQuery(); } } upserted++; } tx.Commit(); } } var active = GetDefaultConsigneeName(); if (!string.IsNullOrWhiteSpace(active)) { SetActiveConsignee(active); } return upserted; } /// /// Синхронизирует поля заказа в `PriceList` (Zakaz/SummaZakaza) с корзиной выбранной аптеки. /// Данные корзины хранятся в TempOrderItems с фильтром по ConsigneeName, а PriceList обновляется /// только для текущего активного просмотра. /// public static void SyncCartToPriceList(string consigneeName) { var consignee = (consigneeName ?? string.Empty).Trim().Replace("'", "''"); using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString)) { connection.Open(); using (var tx = connection.BeginTransaction()) { using (var clear = new SQLiteCommand( @"UPDATE [PriceList] SET [Zakaz] = NULL, [SummaZakaza] = NULL;", connection, tx)) { clear.ExecuteNonQuery(); } using (var sync = new SQLiteCommand( @"UPDATE [PriceList] SET [Zakaz] = ( SELECT t.[Zakaz] FROM [TempOrderItems] t WHERE t.[ConsigneeName] = @consignee AND t.[id_PriceList_Item] = [PriceList].[id_PriceList_Item] LIMIT 1 ), [SummaZakaza] = ( SELECT t.[SummaZakaza] FROM [TempOrderItems] t WHERE t.[ConsigneeName] = @consignee AND t.[id_PriceList_Item] = [PriceList].[id_PriceList_Item] LIMIT 1 ) WHERE EXISTS ( SELECT 1 FROM [TempOrderItems] t WHERE t.[ConsigneeName] = @consignee AND t.[id_PriceList_Item] = [PriceList].[id_PriceList_Item] );", connection, tx)) { sync.Parameters.AddWithValue("@consignee", consignee); sync.ExecuteNonQuery(); } tx.Commit(); } } } } }