20261008-ide1.0发布 #1

Merged
zzh merged 42 commits from test into master 2026-10-08 09:18:00 +08:00
4 changed files with 125 additions and 6 deletions
Showing only changes of commit dd4644e914 - Show all commits

View File

@ -54,3 +54,14 @@ public class OmsUserDetailDto : UserDto
public string? WecomKfUrl { get; set; }
}
/// <summary>
/// 管理员重置用户密码入参。
/// </summary>
public class ResetUserPasswordInput
{
/// <summary>
/// 新密码。
/// </summary>
public string NewPassword { get; set; } = string.Empty;
}

View File

@ -9,11 +9,36 @@ using Oms.Domain.OrdersAggregate.Repositories;
namespace Oms.Application.Integrations.SmallBagTrack;
/// <summary>
/// 揽收单预报下游成功后:按序 UpsertBigBag → Link → Track/Upsert(A0201)。
/// 揽收大包轨迹同步结果(UpsertBigBag → Link → Track A0201)。
/// </summary>
public class PickupBigBagTrackSyncResult
{
public string PickupNo { get; set; } = string.Empty;
public bool Success { get; set; }
public string? FailStep { get; set; }
public string? Message { get; set; }
public SmallBagTrackUpsertResult? UpsertBigBag { get; set; }
public SmallBagTrackUpsertResult? Link { get; set; }
public SmallBagTrackUpsertResult? TrackUpsert { get; set; }
}
/// <summary>
/// 揽收单预报下游成功后 / 手动:按序 UpsertBigBag → Link → Track/Upsert(A0201)。
/// </summary>
public interface IPickupBigBagTrackSyncer
{
Task SyncAfterDownstreamForwardAsync(PickupOrder pickup, CancellationToken cancellationToken = default);
/// <summary>
/// 同步执行三步并返回逐步请求/响应(手动「创建轨迹订单」联调)。
/// </summary>
Task<PickupBigBagTrackSyncResult> SyncDebugAsync(PickupOrder pickup, CancellationToken cancellationToken = default);
}
internal sealed class PickupBigBagTrackSyncer(
@ -29,13 +54,29 @@ internal sealed class PickupBigBagTrackSyncer(
PickupOrder pickup,
CancellationToken cancellationToken = default)
{
await SyncDebugAsync(pickup, cancellationToken);
}
public async Task<PickupBigBagTrackSyncResult> SyncDebugAsync(
PickupOrder pickup,
CancellationToken cancellationToken = default)
{
var result = new PickupBigBagTrackSyncResult
{
PickupNo = pickup?.PickupNo?.Trim() ?? string.Empty
};
if (pickup == null || string.IsNullOrWhiteSpace(pickup.PickupNo))
{
result.Success = false;
result.FailStep = "validate";
result.Message = "pickup or PickupNo empty";
logger.LogWarning("Skip big-bag track sync: pickup or PickupNo empty");
return;
return result;
}
var bagNo = pickup.PickupNo.Trim();
result.PickupNo = bagNo;
var authorization = httpContextAccessor.HttpContext?.Request.Headers.Authorization.ToString();
if (string.IsNullOrWhiteSpace(authorization))
{
@ -62,22 +103,29 @@ internal sealed class PickupBigBagTrackSyncer(
Authorization = authorization
},
cancellationToken);
result.UpsertBigBag = upsertResult;
if (upsertResult.Skipped)
{
result.Success = false;
result.FailStep = "UpsertBigBag";
result.Message = upsertResult.SkipReason ?? "skipped";
logger.LogDebug(
"UpsertBigBag skipped for pickup {PickupNo}: {Reason}",
bagNo,
upsertResult.SkipReason);
return;
return result;
}
if (!upsertResult.Success)
{
result.Success = false;
result.FailStep = "UpsertBigBag";
result.Message = $"HTTP {upsertResult.StatusCode}";
logger.LogWarning(
"Stop big-bag track sync after UpsertBigBag failure for pickup {PickupNo}",
bagNo);
return;
return result;
}
// 2) Link(无明细单号则跳过,继续写轨迹)
@ -98,6 +146,7 @@ internal sealed class PickupBigBagTrackSyncer(
SmallBagTrackLifecycleEvents.OrderType,
authorization,
cancellationToken);
result.Link = linkResult;
if (linkResult.Skipped)
{
@ -108,10 +157,13 @@ internal sealed class PickupBigBagTrackSyncer(
}
else if (!linkResult.Success)
{
result.Success = false;
result.FailStep = "Link";
result.Message = $"HTTP {linkResult.StatusCode}";
logger.LogWarning(
"Stop big-bag track sync after Link failure for pickup {PickupNo}",
bagNo);
return;
return result;
}
}
else
@ -126,28 +178,44 @@ internal sealed class PickupBigBagTrackSyncer(
SmallBagTrackLifecycleEvents.BigBagOrderType,
authorization,
cancellationToken);
result.TrackUpsert = trackResult;
if (trackResult.Skipped)
{
result.Success = false;
result.FailStep = "TrackUpsert";
result.Message = trackResult.SkipReason ?? "skipped";
logger.LogDebug(
"Track A0201 skipped for pickup {PickupNo}: {Reason}",
bagNo,
trackResult.SkipReason);
return;
return result;
}
if (!trackResult.Success)
{
result.Success = false;
result.FailStep = "TrackUpsert";
result.Message = $"HTTP {trackResult.StatusCode}";
logger.LogWarning(
"Track A0201 failed for pickup {PickupNo}: {StatusCode} {Body}",
bagNo,
trackResult.StatusCode,
trackResult.ResponseBody);
return result;
}
result.Success = true;
result.Message = "ok";
return result;
}
catch (Exception ex)
{
result.Success = false;
result.FailStep ??= "exception";
result.Message = ex.Message;
logger.LogWarning(ex, "Big-bag track sync failed for pickup {PickupNo}", bagNo);
return result;
}
}

View File

@ -1005,6 +1005,16 @@ public class PickupOrderService : ApplicationService
};
}
/// <summary>
/// 手动创建大包轨迹订单:按序 UpsertBigBag → Link → Track/Upsert(A0201),返回逐步请求/响应。
/// </summary>
[HttpPost("/order/pickup-order/track-upsert-big-bag")]
public async Task<PickupBigBagTrackSyncResult> TrackUpsertBigBagAsync([FromBody] PickupOrderIdInput input)
{
var pickup = await GetOwnedPickupOrThrowAsync(input.Id);
return await PickupBigBagTrackSyncer.SyncDebugAsync(pickup);
}
/// <summary>
/// 凭证:优先揽收单 CarrierCode 作为 supplierCode;AppKey/Secret 仍按承运服务→渠道分组解析。
/// </summary>

View File

@ -4,6 +4,7 @@ using Fake.Rbac.Application.Dtos.Common;
using Fake.Rbac.Application.Dtos.Role;
using Fake.Rbac.Application.Dtos.User;
using Fake.Rbac.Application.Services;
using Fake.Rbac.Domain.Managers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Fake.ObjectStorage;
@ -23,6 +24,7 @@ namespace Oms.Application.Services.Rbac;
[ApiExplorerSettings(GroupName = "RBAC-User")]
public class OmsUserService(
UserService userService,
AccountManager accountManager,
UserProfileRepository profileRepository,
IEmployeeRepository employeeRepository,
IObjectStorage fileStorage) : ApplicationService
@ -167,6 +169,34 @@ public class OmsUserService(
CancellationToken cancellationToken = default) =>
userService.UpdatePasswordAsync(id, input, cancellationToken);
/// <summary>
/// 管理员重置用户密码(无需旧密码)。
/// </summary>
[HttpPost("/rbac/user/reset-password")]
public async Task ResetPasswordAsync(
[FromQuery] Guid id,
[FromBody] ResetUserPasswordInput input,
CancellationToken cancellationToken = default)
{
if (id == Guid.Empty)
{
throw new BusinessException("用户 Id 无效");
}
var newPassword = input?.NewPassword?.Trim();
if (string.IsNullOrWhiteSpace(newPassword))
{
throw new BusinessException("新密码不能为空");
}
if (newPassword.Length < 6)
{
throw new BusinessException("密码长度不能少于6位");
}
await accountManager.ResetPasswordAsync(id, newPassword, cancellationToken);
}
/// <summary>
/// 更新用户头像。
/// </summary>