Compare commits
2 Commits
35156eedf4
...
9e5d6d20d5
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e5d6d20d5 | |||
| ae4e733a71 |
@ -12,8 +12,19 @@ public class KpiAreaInfoImportInput
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int AreaId { get; set; }
|
public int AreaId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 导入模式:incremental=增量(跳过重复);full=全量(先清空本分区明细再导入)。
|
||||||
|
/// </summary>
|
||||||
|
public string ImportMode { get; set; } = ImportModes.Incremental;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Excel 文件。
|
/// Excel 文件。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IFormFile File { get; set; } = null!;
|
public IFormFile File { get; set; } = null!;
|
||||||
|
|
||||||
|
public static class ImportModes
|
||||||
|
{
|
||||||
|
public const string Incremental = "incremental";
|
||||||
|
public const string Full = "full";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,12 @@ public class MemberOverviewOutput
|
|||||||
{
|
{
|
||||||
public int? MemberLevelId { get; set; }
|
public int? MemberLevelId { get; set; }
|
||||||
|
|
||||||
|
public string? MemberLevelCode { get; set; }
|
||||||
|
|
||||||
public string? MemberLevelName { get; set; }
|
public string? MemberLevelName { get; set; }
|
||||||
|
|
||||||
|
public string? IconUrl { get; set; }
|
||||||
|
|
||||||
public string? PriceTierKey { get; set; }
|
public string? PriceTierKey { get; set; }
|
||||||
|
|
||||||
public int TotalPoints { get; set; }
|
public int TotalPoints { get; set; }
|
||||||
|
|||||||
@ -31,9 +31,9 @@ public class OrderReceiverOutput
|
|||||||
public string? Email { get; set; }
|
public string? Email { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 国家/地区代码。
|
/// 国家/地区二字码。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? CountryCode { get; set; }
|
public string? CountryCode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 省份。
|
/// 省份。
|
||||||
|
|||||||
@ -31,9 +31,9 @@ public class OrderSenderOutput
|
|||||||
public string? Email { get; set; }
|
public string? Email { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 国家/地区代码。
|
/// 国家/地区二字码。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? CountryCode { get; set; }
|
public string? CountryCode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 省份。
|
/// 省份。
|
||||||
|
|||||||
@ -91,6 +91,7 @@ public class KpiAreaService : ApplicationService
|
|||||||
public async Task DeleteAsync(IdInput input)
|
public async Task DeleteAsync(IdInput input)
|
||||||
{
|
{
|
||||||
var entity = await GetAreaOrThrowAsync(input.Id);
|
var entity = await GetAreaOrThrowAsync(input.Id);
|
||||||
|
await KpiAreaRepository.DeleteInfosByAreaIdAsync(entity.Id);
|
||||||
await KpiAreaRepository.DeleteAsync(entity);
|
await KpiAreaRepository.DeleteAsync(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,6 +204,7 @@ public class KpiAreaService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
await GetAreaOrThrowAsync(input.AreaId);
|
await GetAreaOrThrowAsync(input.AreaId);
|
||||||
|
var importMode = NormalizeImportMode(input.ImportMode);
|
||||||
|
|
||||||
await using var stream = input.File.OpenReadStream();
|
await using var stream = input.File.OpenReadStream();
|
||||||
var parsedRows = await KpiAreaInfoImportHelper.ParseImportRowsAsync(stream);
|
var parsedRows = await KpiAreaInfoImportHelper.ParseImportRowsAsync(stream);
|
||||||
@ -218,10 +220,17 @@ public class KpiAreaService : ApplicationService
|
|||||||
.ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);
|
.ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var existingKeys = new HashSet<string>(StringComparer.Ordinal);
|
var existingKeys = new HashSet<string>(StringComparer.Ordinal);
|
||||||
|
if (importMode == KpiAreaInfoImportInput.ImportModes.Full)
|
||||||
|
{
|
||||||
|
await KpiAreaRepository.DeleteInfosByAreaIdAsync(input.AreaId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
foreach (var item in await KpiAreaRepository.GetAllInfosByAreaIdAsync(input.AreaId))
|
foreach (var item in await KpiAreaRepository.GetAllInfosByAreaIdAsync(input.AreaId))
|
||||||
{
|
{
|
||||||
TryAddDuplicateKey(existingKeys, item);
|
TryAddDuplicateKey(existingKeys, item);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var output = new KpiAreaInfoImportOutput();
|
var output = new KpiAreaInfoImportOutput();
|
||||||
foreach (var (rowNumber, entity) in parsedRows)
|
foreach (var (rowNumber, entity) in parsedRows)
|
||||||
@ -236,7 +245,9 @@ public class KpiAreaService : ApplicationService
|
|||||||
output.Failures.Add(new KpiAreaInfoImportFailRow
|
output.Failures.Add(new KpiAreaInfoImportFailRow
|
||||||
{
|
{
|
||||||
RowNumber = rowNumber,
|
RowNumber = rowNumber,
|
||||||
Reason = "与已有规则重复,已跳过"
|
Reason = importMode == KpiAreaInfoImportInput.ImportModes.Full
|
||||||
|
? "文件内规则重复,已跳过"
|
||||||
|
: "与已有规则重复,已跳过"
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -258,6 +269,18 @@ public class KpiAreaService : ApplicationService
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string NormalizeImportMode(string? mode)
|
||||||
|
{
|
||||||
|
if (string.Equals(mode, KpiAreaInfoImportInput.ImportModes.Full, StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals(mode, "全量", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals(mode, "replace", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return KpiAreaInfoImportInput.ImportModes.Full;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KpiAreaInfoImportInput.ImportModes.Incremental;
|
||||||
|
}
|
||||||
|
|
||||||
private static Expression<Func<KpiArea, bool>> BuildAreaPredicate(KpiAreaListInput input)
|
private static Expression<Func<KpiArea, bool>> BuildAreaPredicate(KpiAreaListInput input)
|
||||||
{
|
{
|
||||||
var appKey = input.AppKey?.Trim();
|
var appKey = input.AppKey?.Trim();
|
||||||
|
|||||||
@ -57,7 +57,9 @@ public class MarketingPortalMemberService : ApplicationService
|
|||||||
return new MemberOverviewOutput
|
return new MemberOverviewOutput
|
||||||
{
|
{
|
||||||
MemberLevelId = currentLevel?.Id,
|
MemberLevelId = currentLevel?.Id,
|
||||||
|
MemberLevelCode = currentLevel?.LevelCode,
|
||||||
MemberLevelName = currentLevel?.LevelName,
|
MemberLevelName = currentLevel?.LevelName,
|
||||||
|
IconUrl = currentLevel?.IconUrl,
|
||||||
PriceTierKey = MarketingCustomerHelper.NormalizePriceTierKeyOrDefault(mainCustomer.PriceTierKey),
|
PriceTierKey = MarketingCustomerHelper.NormalizePriceTierKeyOrDefault(mainCustomer.PriceTierKey),
|
||||||
TotalPoints = account.TotalPoints,
|
TotalPoints = account.TotalPoints,
|
||||||
RollingPoints = rollingPoints,
|
RollingPoints = rollingPoints,
|
||||||
|
|||||||
@ -79,6 +79,20 @@ public partial class OrderService
|
|||||||
: await CountryRepository.GetListAsync(x => countryCodes.Contains(x.CountryCode));
|
: await CountryRepository.GetListAsync(x => countryCodes.Contains(x.CountryCode));
|
||||||
var countryMap = countries.ToDictionary(x => x.CountryCode, StringComparer.OrdinalIgnoreCase);
|
var countryMap = countries.ToDictionary(x => x.CountryCode, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
var addressCountryIds = senders
|
||||||
|
.Select(x => x.Country)
|
||||||
|
.Concat(recipients.Select(x => x.Country))
|
||||||
|
.Where(x => x.HasValue)
|
||||||
|
.Select(x => x!.Value)
|
||||||
|
.Distinct()
|
||||||
|
.ToArray();
|
||||||
|
var addressCountries = addressCountryIds.Length == 0
|
||||||
|
? []
|
||||||
|
: await CountryRepository.GetListAsync(x => addressCountryIds.Contains(x.Id));
|
||||||
|
var countryIdCodeMap = addressCountries.ToDictionary(
|
||||||
|
x => x.Id,
|
||||||
|
x => x.CountryCode ?? string.Empty);
|
||||||
|
|
||||||
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
|
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
|
||||||
orders.SelectMany(x => new[] { x.CreateUserId, x.UpdateUserId }));
|
orders.SelectMany(x => new[] { x.CreateUserId, x.UpdateUserId }));
|
||||||
|
|
||||||
@ -252,8 +266,8 @@ public partial class OrderService
|
|||||||
CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(order.CreateUserId, auditUserNameMap),
|
CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(order.CreateUserId, auditUserNameMap),
|
||||||
UpdateTime = OmsDocHelper.NullIfDefault(order.UpdateTime),
|
UpdateTime = OmsDocHelper.NullIfDefault(order.UpdateTime),
|
||||||
UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(order.UpdateUserId, auditUserNameMap),
|
UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(order.UpdateUserId, auditUserNameMap),
|
||||||
Sender = MapSender(sender),
|
Sender = MapSender(sender, countryIdCodeMap),
|
||||||
Receiver = MapReceiver(recipient),
|
Receiver = MapReceiver(recipient, countryIdCodeMap),
|
||||||
Items = (items ?? []).Select(MapDeclaration).ToList(),
|
Items = (items ?? []).Select(MapDeclaration).ToList(),
|
||||||
WeightList = (orderWeights ?? []).Select(MapWeight).ToList(),
|
WeightList = (orderWeights ?? []).Select(MapWeight).ToList(),
|
||||||
FeeList = feeOutputs,
|
FeeList = feeOutputs,
|
||||||
@ -705,7 +719,9 @@ public partial class OrderService
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OrderSenderOutput? MapSender(OrderSender? sender)
|
private static OrderSenderOutput? MapSender(
|
||||||
|
OrderSender? sender,
|
||||||
|
IReadOnlyDictionary<int, string> countryIdCodeMap)
|
||||||
{
|
{
|
||||||
return sender == null
|
return sender == null
|
||||||
? null
|
? null
|
||||||
@ -716,7 +732,7 @@ public partial class OrderService
|
|||||||
Phone = sender.Phone,
|
Phone = sender.Phone,
|
||||||
TelePhone = sender.TelePhone,
|
TelePhone = sender.TelePhone,
|
||||||
Email = sender.Email,
|
Email = sender.Email,
|
||||||
CountryCode = sender.Country,
|
CountryCode = ResolveCountryCode(sender.Country, countryIdCodeMap),
|
||||||
Province = sender.Province,
|
Province = sender.Province,
|
||||||
City = sender.City,
|
City = sender.City,
|
||||||
ZipCode = sender.ZipCode,
|
ZipCode = sender.ZipCode,
|
||||||
@ -727,7 +743,9 @@ public partial class OrderService
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OrderReceiverOutput? MapReceiver(OrderRecipient? recipient)
|
private static OrderReceiverOutput? MapReceiver(
|
||||||
|
OrderRecipient? recipient,
|
||||||
|
IReadOnlyDictionary<int, string> countryIdCodeMap)
|
||||||
{
|
{
|
||||||
return recipient == null
|
return recipient == null
|
||||||
? null
|
? null
|
||||||
@ -738,7 +756,7 @@ public partial class OrderService
|
|||||||
Phone = recipient.Phone,
|
Phone = recipient.Phone,
|
||||||
TelePhone = recipient.TelePhone,
|
TelePhone = recipient.TelePhone,
|
||||||
Email = recipient.Email,
|
Email = recipient.Email,
|
||||||
CountryCode = recipient.Country,
|
CountryCode = ResolveCountryCode(recipient.Country, countryIdCodeMap),
|
||||||
Province = recipient.Province,
|
Province = recipient.Province,
|
||||||
City = recipient.City,
|
City = recipient.City,
|
||||||
StreetNumber = recipient.StreetNumber,
|
StreetNumber = recipient.StreetNumber,
|
||||||
@ -755,6 +773,20 @@ public partial class OrderService
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string? ResolveCountryCode(
|
||||||
|
int? countryId,
|
||||||
|
IReadOnlyDictionary<int, string> countryIdCodeMap)
|
||||||
|
{
|
||||||
|
if (!countryId.HasValue)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return countryIdCodeMap.TryGetValue(countryId.Value, out var code) && !string.IsNullOrWhiteSpace(code)
|
||||||
|
? code
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
private OrderItemOutput MapDeclaration(OrderDeclaration x)
|
private OrderItemOutput MapDeclaration(OrderDeclaration x)
|
||||||
{
|
{
|
||||||
return new OrderItemOutput
|
return new OrderItemOutput
|
||||||
|
|||||||
@ -21,5 +21,7 @@ public interface IKpiAreaRepository : IRepository<KpiArea>, IKpiAreaPublishRepos
|
|||||||
|
|
||||||
Task DeleteInfoAsync(int id, CancellationToken cancellationToken = default);
|
Task DeleteInfoAsync(int id, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task DeleteInfosByAreaIdAsync(int areaId, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<List<KpiAreaInfo>> GetAllInfosByAreaIdAsync(int areaId, CancellationToken cancellationToken = default);
|
Task<List<KpiAreaInfo>> GetAllInfosByAreaIdAsync(int areaId, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,6 +57,12 @@ public class KpiAreaRepository : OmsSqlSugarRepository<KpiArea>, IKpiAreaReposit
|
|||||||
await db.Deleteable<KpiAreaInfo>().Where(x => x.Id == id).ExecuteCommandAsync(cancellationToken);
|
await db.Deleteable<KpiAreaInfo>().Where(x => x.Id == id).ExecuteCommandAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task DeleteInfosByAreaIdAsync(int areaId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var db = await GetDbContextAsync(cancellationToken);
|
||||||
|
await db.Deleteable<KpiAreaInfo>().Where(x => x.AreaId == areaId).ExecuteCommandAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<List<KpiAreaInfo>> GetAllInfosByAreaIdAsync(int areaId, CancellationToken cancellationToken = default)
|
public async Task<List<KpiAreaInfo>> GetAllInfosByAreaIdAsync(int areaId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var db = await GetDbContextAsync(cancellationToken);
|
var db = await GetDbContextAsync(cancellationToken);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user