feat: 揽收大包轨迹手动同步接口,并支持管理员重置密码
All checks were successful
Build and Deploy / deploy (push) Successful in 59s
All checks were successful
Build and Deploy / deploy (push) Successful in 59s
新增 track-upsert-big-bag 返回三步联调结果;补齐 reset-password API。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
26c840cdb1
commit
dd4644e914
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user