diff --git a/src/Oms.Application/Services/Orders/OrderService.Template.cs b/src/Oms.Application/Services/Orders/OrderService.Template.cs index ecc3126..43ab1e0 100644 --- a/src/Oms.Application/Services/Orders/OrderService.Template.cs +++ b/src/Oms.Application/Services/Orders/OrderService.Template.cs @@ -398,11 +398,13 @@ public partial class OrderService } var currencyDict = await DictRepository.GetListAsync(x => x.DictType == "currency"); - var firstCurrency = currencyDict.OrderBy(x => x.DictSort).FirstOrDefault(); - if (firstCurrency != null) + var defaultCurrency = currencyDict.FirstOrDefault(x => + string.Equals(x.DictCode, "USD", StringComparison.OrdinalIgnoreCase)) + ?? currencyDict.OrderBy(x => x.DictSort).FirstOrDefault(); + if (defaultCurrency != null) { - overrides["declaredCurrency"] = firstCurrency.DictCode; - overrides["codCurrency"] = firstCurrency.DictCode; + overrides["declaredCurrency"] = defaultCurrency.DictCode; + overrides["codCurrency"] = defaultCurrency.DictCode; } var exportDict = await DictRepository.GetListAsync(x => x.DictType == "export_customs_mode"); diff --git a/src/Oms.Application/Services/Orders/Templates/OrderTemplateFieldRegistry.cs b/src/Oms.Application/Services/Orders/Templates/OrderTemplateFieldRegistry.cs index 2de5e14..c7d18f3 100644 --- a/src/Oms.Application/Services/Orders/Templates/OrderTemplateFieldRegistry.cs +++ b/src/Oms.Application/Services/Orders/Templates/OrderTemplateFieldRegistry.cs @@ -81,8 +81,6 @@ public static class OrderTemplateFieldRegistry Add("isCod", "是否COD", false, "boolean", example: "false"); Add("codCurrency", "COD币种", false, "select", "currency", example: "USD"); Add("codSum", "COD金额", false, "number", example: "0"); - Add("declaredCurrency", "申报币种", true, "select", "currency", example: "USD"); - Add("declaredSum", "申报金额", false, "number"); Add("quantity", "包裹数量", true, "number", example: "1"); Add("receiver.recipientsName", "收件人名称", true, group: "receiver", example: "Demo Receiver"); @@ -119,15 +117,17 @@ public static class OrderTemplateFieldRegistry Add("sender.streetAddress3", "发件地址3", false, group: "sender"); Add("sender.houseNumber", "发件门牌号", false, group: "sender", example: "88"); + Add("declaredCurrency", "申报币种", true, "select", "currency", "declaration", "USD"); + Add("declaredSum", "申报总金额", false, "number", group: "declaration", example: "可选,不填自动汇总"); Add("items[0].cnName", "申报品名(中)", false, group: "declaration", example: "手机壳"); Add("items[0].enName", "申报品名(英)", true, group: "declaration", example: "Phone Case"); Add("items[0].sku", "SKU", false, group: "declaration", example: "SKU001"); Add("items[0].unit", "单位", false, group: "declaration", example: "pcs"); - Add("items[0].unitPrice", "单价", true, "number", group: "declaration", example: "12.5"); - Add("items[0].unitWeight", "单重", true, "number", group: "declaration", example: "0.3"); + Add("items[0].unitPrice", "单价(元)", true, "number", group: "declaration", example: "12.5"); + Add("items[0].unitWeight", "单重(kg)", true, "number", group: "declaration", example: "0.3"); Add("items[0].quantity", "申报数量", true, "number", group: "declaration", example: "1"); - Add("items[0].amount", "总金额", false, "number", group: "declaration", example: "12.5"); - Add("items[0].weight", "总重量", false, "number", group: "declaration", example: "0.3"); + Add("items[0].amount", "总金额(元)", false, "number", group: "declaration", example: "自动计算=单价×数量"); + Add("items[0].weight", "总重量(kg)", false, "number", group: "declaration", example: "自动计算=单重×数量"); Add("items[0].imHsCode", "进口HsCode", false, group: "declaration"); Add("items[0].exHsCode", "出口HsCode", false, group: "declaration"); Add("items[0].skuImage", "商品图片URL", false, group: "declaration"); diff --git a/src/Oms.Application/Services/Orders/Templates/OrderTemplateHeaderMatcher.cs b/src/Oms.Application/Services/Orders/Templates/OrderTemplateHeaderMatcher.cs index 499eb4c..76830e7 100644 --- a/src/Oms.Application/Services/Orders/Templates/OrderTemplateHeaderMatcher.cs +++ b/src/Oms.Application/Services/Orders/Templates/OrderTemplateHeaderMatcher.cs @@ -31,6 +31,8 @@ public static class OrderTemplateHeaderMatcher ["实重kg"] = "actualWeight", ["实重"] = "actualWeight", ["申报币种"] = "declaredCurrency", + ["申报金额"] = "declaredSum", + ["申报总金额"] = "declaredSum", ["包裹数量"] = "quantity", ["收件人名称"] = "receiver.recipientsName", ["收件姓名"] = "receiver.recipientsName", @@ -44,8 +46,14 @@ public static class OrderTemplateHeaderMatcher ["品名英"] = "items[0].enName", ["申报品名中"] = "items[0].cnName", ["单价"] = "items[0].unitPrice", + ["单价元"] = "items[0].unitPrice", ["单重"] = "items[0].unitWeight", + ["单重kg"] = "items[0].unitWeight", ["申报数量"] = "items[0].quantity", + ["总金额"] = "items[0].amount", + ["总金额元"] = "items[0].amount", + ["总重量"] = "items[0].weight", + ["总重量kg"] = "items[0].weight", }; public static string? MatchStandardFieldKey(string? sourceHeader, string? templateKey) diff --git a/src/Oms.Application/Services/Orders/Templates/OrderTemplateRowMapper.cs b/src/Oms.Application/Services/Orders/Templates/OrderTemplateRowMapper.cs index 333e644..e9146fb 100644 --- a/src/Oms.Application/Services/Orders/Templates/OrderTemplateRowMapper.cs +++ b/src/Oms.Application/Services/Orders/Templates/OrderTemplateRowMapper.cs @@ -74,9 +74,51 @@ public static class OrderTemplateRowMapper SetFieldValue(input, fieldKey, coerced); } + ApplyDerivedDeclarationFields(input); return input; } + private static void ApplyDerivedDeclarationFields(OrderParcelCreateInput input) + { + if (string.IsNullOrWhiteSpace(input.DeclaredCurrency)) + { + input.DeclaredCurrency = "USD"; + } + + decimal declaredTotal = 0; + var hasDeclaredTotal = false; + + foreach (var item in input.Items) + { + if (!item.Amount.HasValue && item.UnitPrice.HasValue && item.Quantity.HasValue) + { + item.Amount = Math.Round( + item.UnitPrice.Value * item.Quantity.Value, + 4, + MidpointRounding.AwayFromZero); + } + + if (!item.Weight.HasValue && item.UnitWeight.HasValue && item.Quantity.HasValue) + { + item.Weight = Math.Round( + item.UnitWeight.Value * item.Quantity.Value, + 4, + MidpointRounding.AwayFromZero); + } + + if (item.Amount.HasValue) + { + declaredTotal += item.Amount.Value; + hasDeclaredTotal = true; + } + } + + if (!input.DeclaredSum.HasValue && hasDeclaredTotal) + { + input.DeclaredSum = declaredTotal; + } + } + private static bool TryGetMappedValue( IReadOnlyDictionary sourceValues, string sourceColumn, diff --git a/src/Oms.Application/Shared/OmsRbacRegistrationGuard.cs b/src/Oms.Application/Shared/OmsRbacRegistrationGuard.cs index f47ce1d..6c00024 100644 --- a/src/Oms.Application/Shared/OmsRbacRegistrationGuard.cs +++ b/src/Oms.Application/Shared/OmsRbacRegistrationGuard.cs @@ -77,9 +77,10 @@ public static class OmsRbacRegistrationGuard string account, CancellationToken cancellationToken) { + // 唯一索引不按 IsDeleted 区分,软删除账号仍会触发 Duplicate entry。 var hit = await rbacDbContext.Database .SqlQuery( - $"SELECT 1 AS Value FROM `user` WHERE `IsDeleted` = 0 AND `Account` = {account} LIMIT 1") + $"SELECT 1 AS Value FROM `user` WHERE `Account` = {account} LIMIT 1") .FirstOrDefaultAsync(cancellationToken); return hit.HasValue; } @@ -91,7 +92,7 @@ public static class OmsRbacRegistrationGuard { var hit = await rbacDbContext.Database .SqlQuery( - $"SELECT 1 AS Value FROM `user` WHERE `IsDeleted` = 0 AND `Email` = {email} LIMIT 1") + $"SELECT 1 AS Value FROM `user` WHERE `Email` = {email} LIMIT 1") .FirstOrDefaultAsync(cancellationToken); return hit.HasValue; } diff --git a/src/SimpleAdmin.Api/WeChat/WeChatCustomerService.cs b/src/SimpleAdmin.Api/WeChat/WeChatCustomerService.cs index ce02226..daabe0b 100644 --- a/src/SimpleAdmin.Api/WeChat/WeChatCustomerService.cs +++ b/src/SimpleAdmin.Api/WeChat/WeChatCustomerService.cs @@ -100,18 +100,19 @@ public class WeChatCustomerService( await OmsRbacRegistrationGuard.EnsureLoginIdentityAvailableAsync(rbacDbContext, phone, email, cancellationToken); var customerRoleId = await GetCustomerRoleIdOrThrowAsync(cancellationToken); - var user = await userService.CreateAsync(new UserCreateDto - { - Name = customerName, - Account = phone, - Password = password, - Email = email, - Avatar = NormalizeOptional(input.Wechat.Avatar), - RoleIds = [] - }); - + UserDto? user = null; try { + user = await userService.CreateAsync(new UserCreateDto + { + Name = customerName, + Account = phone, + Password = password, + Email = email, + Avatar = NormalizeOptional(input.Wechat.Avatar), + RoleIds = [] + }); + await userService.AssignRolesAsync(user.Id, [customerRoleId]); var userId = await GetRbacUserMapIdOrThrowAsync(user.Id, cancellationToken); var entity = new Customer @@ -131,7 +132,11 @@ public class WeChatCustomerService( } catch (Exception ex) { - await TryRollbackRbacUserAsync(user.Id); + if (user != null) + { + await TryRollbackRbacUserAsync(user.Id); + } + throw ex is BusinessException ? ex : OmsRbacRegistrationGuard.ToSaveBusinessException(ex); } }