using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Электронная_Фармация.Properties;
namespace Электронная_Фармация.Classes
{
///
/// Собирает доступные скидки покупателя/прайса/региона и вешает на позицию то, что пришло.
/// Отсутствующий источник = 0.
///
public static class DiscountResolver
{
public static async Task LoadAsync(ApiClient client, string loginHint)
{
var lookup = new DiscountLookup();
if (client == null)
{
return lookup;
}
var regionId = (Settings.Default.RegionId ?? string.Empty).Trim();
lookup.RegionId = regionId;
string buyerId = null;
try
{
var buyers = await client.GetBuyersAsync();
buyerId = ResolveBuyerId(buyers, loginHint);
lookup.BuyerId = buyerId;
AppDebugLog.Info(
"Discount",
string.IsNullOrWhiteSpace(buyerId)
? "buyer_id не найден — клиентская скидка будет 0"
: $"buyer_id={buyerId}");
}
catch (Exception ex)
{
AppDebugLog.Warning("Discount", $"Не удалось загрузить покупателей: {ex.Message}");
}
List assignments = null;
if (!string.IsNullOrWhiteSpace(buyerId))
{
try
{
assignments = await client.GetBuyerPriceListsAsync(buyerId);
AppDebugLog.Info("Discount", $"Назначений прайсов покупателя: {assignments?.Count ?? 0}");
}
catch (Exception ex)
{
AppDebugLog.Warning("Discount", $"Не удалось загрузить buyer price-lists: {ex.Message}");
}
}
List priceLists = null;
try
{
priceLists = await client.GetPriceListsAsync();
AppDebugLog.Info("Discount", $"Прайс-листов: {priceLists?.Count ?? 0}");
}
catch (Exception ex)
{
AppDebugLog.Warning("Discount", $"Не удалось загрузить price-lists: {ex.Message}");
}
EnrichAssignmentsFromPriceLists(assignments, priceLists);
if (assignments != null)
{
foreach (var a in assignments)
{
if (string.IsNullOrWhiteSpace(a?.PriceListId))
{
continue;
}
var plId = a.PriceListId.Trim();
lookup.ByPriceListId[plId] = new ItemDiscountParts
{
PriceListId = plId,
ClientDiscountPct = PositiveOrZero(a.MarkupPct),
PriceListDiscountPct = PositiveOrZero(a.DefaultMarkupPct),
RegionDiscountPct = 0m
};
IndexSupplierKeys(lookup, a.SupplierId, a.SupplierName, plId);
}
}
if (priceLists != null)
{
foreach (var pl in priceLists)
{
var plId = pl?.ResolvedId;
if (string.IsNullOrWhiteSpace(plId))
{
continue;
}
if (!lookup.ByPriceListId.TryGetValue(plId, out var parts))
{
parts = new ItemDiscountParts { PriceListId = plId };
lookup.ByPriceListId[plId] = parts;
}
if (parts.PriceListDiscountPct <= 0m && pl.DefaultMarkupPct.HasValue && pl.DefaultMarkupPct.Value > 0m)
{
parts.PriceListDiscountPct = pl.DefaultMarkupPct.Value;
}
IndexSupplierKeys(lookup, pl.SupplierId, pl.SupplierName, plId);
}
}
foreach (var plId in lookup.ByPriceListId.Keys.ToList())
{
try
{
var regions = await client.GetPriceListRegionsAsync(plId);
var regionPct = ResolveRegionDiscount(regions, regionId);
lookup.ByPriceListId[plId].RegionDiscountPct = regionPct;
}
catch (Exception ex)
{
AppDebugLog.Warning("Discount", $"Регионы для прайса {plId}: {ex.Message}");
}
}
AppDebugLog.Info(
"Discount",
$"Готово: прайсов={lookup.ByPriceListId.Count}, привязок по поставщику={lookup.BySupplierKey.Count}, region={regionId}");
return lookup;
}
public static ItemDiscountParts ResolveForItem(DiscountLookup lookup, PriceSummaryItem item)
{
if (lookup == null || item == null)
{
return new ItemDiscountParts();
}
var priceListId = (item.PriceListId ?? string.Empty).Trim();
if (!string.IsNullOrWhiteSpace(priceListId) &&
lookup.ByPriceListId.TryGetValue(priceListId, out var byId))
{
return Clone(byId);
}
var supplierId = (item.SupplierId ?? string.Empty).Trim();
if (!string.IsNullOrWhiteSpace(supplierId) &&
lookup.BySupplierKey.TryGetValue(NormalizeKey(supplierId), out var plFromSupplier) &&
lookup.ByPriceListId.TryGetValue(plFromSupplier, out var bySupplier))
{
return Clone(bySupplier);
}
var supplierName = (item.SupplierName ?? string.Empty).Trim();
if (!string.IsNullOrWhiteSpace(supplierName) &&
lookup.BySupplierKey.TryGetValue(NormalizeKey(supplierName), out var plFromName) &&
lookup.ByPriceListId.TryGetValue(plFromName, out var byName))
{
return Clone(byName);
}
return new ItemDiscountParts();
}
private static string ResolveBuyerId(List buyers, string loginHint)
{
if (buyers == null || buyers.Count == 0)
{
return null;
}
var login = (loginHint ?? string.Empty).Trim();
if (!string.IsNullOrWhiteSpace(login))
{
var matched = buyers.FirstOrDefault(b =>
string.Equals((b.Username ?? string.Empty).Trim(), login, StringComparison.OrdinalIgnoreCase) ||
string.Equals((b.Login ?? string.Empty).Trim(), login, StringComparison.OrdinalIgnoreCase) ||
string.Equals((b.Name ?? string.Empty).Trim(), login, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrWhiteSpace(matched?.ResolvedId))
{
return matched.ResolvedId;
}
}
if (buyers.Count == 1 && !string.IsNullOrWhiteSpace(buyers[0].ResolvedId))
{
return buyers[0].ResolvedId;
}
return buyers
.Select(b => b.ResolvedId)
.FirstOrDefault(id => !string.IsNullOrWhiteSpace(id));
}
private static void EnrichAssignmentsFromPriceLists(
List assignments,
List priceLists)
{
if (assignments == null || priceLists == null || priceLists.Count == 0)
{
return;
}
var byId = priceLists
.Where(p => !string.IsNullOrWhiteSpace(p?.ResolvedId))
.GroupBy(p => p.ResolvedId, StringComparer.OrdinalIgnoreCase)
.ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);
foreach (var a in assignments)
{
if (a == null || string.IsNullOrWhiteSpace(a.PriceListId))
{
continue;
}
if (!byId.TryGetValue(a.PriceListId.Trim(), out var pl))
{
continue;
}
if (string.IsNullOrWhiteSpace(a.SupplierId))
{
a.SupplierId = pl.SupplierId;
}
if (string.IsNullOrWhiteSpace(a.SupplierName))
{
a.SupplierName = pl.SupplierName;
}
if ((!a.DefaultMarkupPct.HasValue || a.DefaultMarkupPct.Value <= 0m) &&
pl.DefaultMarkupPct.HasValue)
{
a.DefaultMarkupPct = pl.DefaultMarkupPct;
}
}
}
private static decimal ResolveRegionDiscount(List regions, string regionId)
{
if (regions == null || regions.Count == 0)
{
return 0m;
}
PriceListRegionDto match = null;
if (!string.IsNullOrWhiteSpace(regionId))
{
match = regions.FirstOrDefault(r =>
string.Equals((r.RegionId ?? string.Empty).Trim(), regionId, StringComparison.OrdinalIgnoreCase) &&
(r.InWork == null || r.InWork.Value));
}
if (match == null)
{
match = regions.FirstOrDefault(r => r.InWork == true) ?? regions.FirstOrDefault();
}
return PositiveOrZero(match?.MarkupPct);
}
private static void IndexSupplierKeys(DiscountLookup lookup, string supplierId, string supplierName, string priceListId)
{
if (lookup == null || string.IsNullOrWhiteSpace(priceListId))
{
return;
}
if (!string.IsNullOrWhiteSpace(supplierId))
{
lookup.BySupplierKey[NormalizeKey(supplierId)] = priceListId;
}
if (!string.IsNullOrWhiteSpace(supplierName))
{
lookup.BySupplierKey[NormalizeKey(supplierName)] = priceListId;
}
}
private static ItemDiscountParts Clone(ItemDiscountParts source)
{
if (source == null)
{
return new ItemDiscountParts();
}
return new ItemDiscountParts
{
PriceListId = source.PriceListId,
PriceListDiscountPct = source.PriceListDiscountPct,
RegionDiscountPct = source.RegionDiscountPct,
ClientDiscountPct = source.ClientDiscountPct
};
}
private static decimal PositiveOrZero(decimal? value)
{
return value.HasValue && value.Value > 0m ? value.Value : 0m;
}
private static string NormalizeKey(string value)
{
return (value ?? string.Empty).Trim().ToLowerInvariant();
}
}
public sealed class DiscountLookup
{
public string BuyerId { get; set; }
public string RegionId { get; set; }
public Dictionary ByPriceListId { get; } =
new Dictionary(StringComparer.OrdinalIgnoreCase);
public Dictionary BySupplierKey { get; } =
new Dictionary(StringComparer.OrdinalIgnoreCase);
}
}