507 lines
20 KiB
C#
507 lines
20 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Data.SQLite;
|
||
|
||
namespace Электронная_Фармация.Classes
|
||
{
|
||
/// <summary>
|
||
/// Аптека = грузополучатель + LocationId. Прайс общий, заказы уходят с location_id выбранной аптеки.
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Помечает аптеку активной и синхронизирует AppConfig.LocationId.
|
||
/// </summary>
|
||
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<string> GetKnownSupplierIds()
|
||
{
|
||
var result = new List<string>();
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Процент наценки, который клиент задал вручную для аптеки.
|
||
/// null = ещё не сохраняли, брать fallback.
|
||
/// </summary>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Сохраняет процент наценки клиента для конкретной аптеки.
|
||
/// Не сбрасывается при обновлении прайса.
|
||
/// </summary>
|
||
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();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Если у аптеки ещё нет сохранённого процента — записать стартовое значение с сервера.
|
||
/// Уже введённые клиентом значения не трогаем.
|
||
/// </summary>
|
||
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();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Подтягивает грузополучателей с сервера (BuyerLocation) в локальную таблицу Consignees.
|
||
/// Источник истины — веб-кабинет; локально только кэш + выбор активной аптеки.
|
||
/// </summary>
|
||
public static int SyncFromServer(IList<BuyerLocationDto> 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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Синхронизирует поля заказа в `PriceList` (Zakaz/SummaZakaza) с корзиной выбранной аптеки.
|
||
/// Данные корзины хранятся в TempOrderItems с фильтром по ConsigneeName, а PriceList обновляется
|
||
/// только для текущего активного просмотра.
|
||
/// </summary>
|
||
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();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|