PartnerCompanyDisplayHelper.cs 9.38 KB
using System.Text.Json;
using FoodLabeling.Application.Services.DbModels;
using FoodLabeling.Domain.Entities;
using SqlSugar;

namespace FoodLabeling.Application.Helpers;

/// <summary>
/// Company 自动生成元素:按门店解析 <c>fl_partner</c> 并格式化为多行展示文本。
/// </summary>
public static class PartnerCompanyDisplayHelper
{
    /// <summary>
    /// 模板元素是否属于 Company 自动生成(<c>auto_Company</c> 或 AUTO_DB + typeAdd 含 Company)。
    /// </summary>
    public static bool IsCompanyAutoElement(string? valueSourceType, string? typeAdd, string? elementType = null)
    {
        var ta = typeAdd?.Trim();
        if (string.IsNullOrWhiteSpace(ta))
        {
            return false;
        }

        if (string.Equals(ta, "auto_Company", StringComparison.OrdinalIgnoreCase))
        {
            return true;
        }

        return string.Equals(valueSourceType, "AUTO_DB", StringComparison.OrdinalIgnoreCase)
               && ta.StartsWith("auto_", StringComparison.OrdinalIgnoreCase)
               && ta.Contains("Company", StringComparison.OrdinalIgnoreCase);
    }

    /// <summary>
    /// 模板元素是否属于 Company 自动生成。
    /// </summary>
    public static bool IsCompanyAutoElement(FlLabelTemplateElementDbEntity el)
        => IsCompanyAutoElement(el.ValueSourceType, el.TypeAdd, el.ElementType);

    /// <summary>
    /// Company 展示字段勾选结果。
    /// </summary>
    public sealed class CompanyIncludeFields
    {
        public bool IncludeAddress { get; set; }

        public bool IncludeCity { get; set; }

        public bool IncludeState { get; set; }

        public bool IncludeZip { get; set; }

        public bool IncludeEmail { get; set; }
    }

    /// <summary>
    /// 从元素 config 解析需展示的 Company 字段(<c>companyIncludeFields</c> 或布尔开关)。
    /// </summary>
    public static CompanyIncludeFields ParseIncludeFields(IReadOnlyDictionary<string, object?> config)
    {
        var result = new CompanyIncludeFields();

        if (config.TryGetValue("companyIncludeFields", out var arrVal))
        {
            foreach (var item in EnumerateStringArray(arrVal))
            {
                if (string.Equals(item, "address", StringComparison.OrdinalIgnoreCase))
                {
                    result.IncludeAddress = true;
                }
                else if (string.Equals(item, "city", StringComparison.OrdinalIgnoreCase))
                {
                    result.IncludeCity = true;
                }
                else if (string.Equals(item, "state", StringComparison.OrdinalIgnoreCase))
                {
                    result.IncludeState = true;
                }
                else if (string.Equals(item, "zip", StringComparison.OrdinalIgnoreCase))
                {
                    result.IncludeZip = true;
                }
                else if (string.Equals(item, "email", StringComparison.OrdinalIgnoreCase))
                {
                    result.IncludeEmail = true;
                }
            }
        }

        if (TryGetBool(config, "includeAddress", out var includeAddress) && includeAddress)
        {
            result.IncludeAddress = true;
        }

        if (TryGetBool(config, "includeCity", out var includeCity) && includeCity)
        {
            result.IncludeCity = true;
        }

        if (TryGetBool(config, "includeState", out var includeState) && includeState)
        {
            result.IncludeState = true;
        }

        if (TryGetBool(config, "includeZip", out var includeZip) && includeZip)
        {
            result.IncludeZip = true;
        }

        if (TryGetBool(config, "includeEmail", out var includeEmail) && includeEmail)
        {
            result.IncludeEmail = true;
        }

        return result;
    }

    /// <summary>
    /// 将合作伙伴信息格式化为多行文本:公司名、地址、城市州邮编、邮箱。
    /// </summary>
    public static string FormatDisplayText(FlPartnerDbEntity partner, CompanyIncludeFields includes)
    {
        var lines = new List<string>();

        var partnerName = partner.PartnerName?.Trim();
        if (!string.IsNullOrWhiteSpace(partnerName))
        {
            lines.Add(partnerName);
        }

        if (includes.IncludeAddress)
        {
            var street = partner.Street?.Trim();
            if (!string.IsNullOrWhiteSpace(street))
            {
                lines.Add(street);
            }
        }

        if (includes.IncludeCity || includes.IncludeState || includes.IncludeZip)
        {
            var cityStateZipParts = new List<string>();
            if (includes.IncludeCity)
            {
                var city = partner.City?.Trim();
                if (!string.IsNullOrWhiteSpace(city))
                {
                    cityStateZipParts.Add(city);
                }
            }

            if (includes.IncludeState)
            {
                var state = partner.StateCode?.Trim();
                if (!string.IsNullOrWhiteSpace(state))
                {
                    cityStateZipParts.Add(state);
                }
            }

            if (includes.IncludeZip)
            {
                var zip = partner.ZipCode?.Trim();
                if (!string.IsNullOrWhiteSpace(zip))
                {
                    cityStateZipParts.Add(zip);
                }
            }

            if (cityStateZipParts.Count > 0)
            {
                lines.Add(string.Join(", ", cityStateZipParts));
            }
        }

        if (includes.IncludeEmail)
        {
            var email = partner.ContactEmail?.Trim();
            if (!string.IsNullOrWhiteSpace(email))
            {
                lines.Add(email);
            }
        }

        return string.Join("\n", lines);
    }

    /// <summary>
    /// 门店 Guid → <c>location.Partner</c> → 匹配 <c>fl_partner</c>(按 PartnerName 或 Id)。
    /// </summary>
    public static async Task<FlPartnerDbEntity?> ResolvePartnerByLocationIdAsync(
        ISqlSugarClient db,
        string? locationId)
    {
        var id = locationId?.Trim();
        if (string.IsNullOrWhiteSpace(id) || !Guid.TryParse(id, out var locationGuid))
        {
            return null;
        }

        var loc = await db.Queryable<LocationAggregateRoot>()
            .Where(x => !x.IsDeleted && x.Id == locationGuid)
            .FirstAsync();
        if (loc is null)
        {
            return null;
        }

        var partnerKey = loc.Partner?.Trim();
        if (string.IsNullOrWhiteSpace(partnerKey))
        {
            return null;
        }

        var candidates = await db.Queryable<FlPartnerDbEntity>()
            .Where(x => !x.IsDeleted)
            .Where(x => x.Id == partnerKey || x.PartnerName == partnerKey)
            .ToListAsync();

        return candidates.FirstOrDefault(p =>
            string.Equals(p.Id, partnerKey, StringComparison.OrdinalIgnoreCase)
            || string.Equals(p.PartnerName?.Trim(), partnerKey, StringComparison.OrdinalIgnoreCase));
    }

    private static IEnumerable<string> EnumerateStringArray(object? value)
    {
        if (value is null)
        {
            yield break;
        }

        if (value is string s)
        {
            if (!string.IsNullOrWhiteSpace(s))
            {
                yield return s.Trim();
            }

            yield break;
        }

        if (value is JsonElement je)
        {
            if (je.ValueKind == JsonValueKind.Array)
            {
                foreach (var item in je.EnumerateArray())
                {
                    var text = item.ValueKind == JsonValueKind.String ? item.GetString() : item.ToString();
                    if (!string.IsNullOrWhiteSpace(text))
                    {
                        yield return text.Trim();
                    }
                }
            }
            else if (je.ValueKind == JsonValueKind.String)
            {
                var text = je.GetString();
                if (!string.IsNullOrWhiteSpace(text))
                {
                    yield return text.Trim();
                }
            }

            yield break;
        }

        if (value is IEnumerable<object?> enumerable)
        {
            foreach (var item in enumerable)
            {
                var text = item?.ToString();
                if (!string.IsNullOrWhiteSpace(text))
                {
                    yield return text.Trim();
                }
            }
        }
    }

    private static bool TryGetBool(IReadOnlyDictionary<string, object?> config, string key, out bool result)
    {
        result = false;
        if (!config.TryGetValue(key, out var value) || value is null)
        {
            return false;
        }

        switch (value)
        {
            case bool b:
                result = b;
                return true;
            case JsonElement je when je.ValueKind is JsonValueKind.True or JsonValueKind.False:
                result = je.GetBoolean();
                return true;
            case JsonElement je when je.ValueKind == JsonValueKind.String
                                     && bool.TryParse(je.GetString(), out var parsed):
                result = parsed;
                return true;
            case string s when bool.TryParse(s, out var parsedStr):
                result = parsedStr;
                return true;
            default:
                return false;
        }
    }
}