20260627
This commit is contained in:
parent
d766343ffe
commit
fdbdfa8124
@ -12,6 +12,7 @@ CREATE TABLE IF NOT EXISTS `t_customer_account_flow` (
|
||||
`Currency` varchar(8) NOT NULL DEFAULT 'CNY' COMMENT '币种',
|
||||
`Remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`IsDeleted` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`ConcurrencyStamp` char(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
|
||||
`CreateUserId` int NOT NULL DEFAULT '0',
|
||||
`CreateTime` datetime NOT NULL,
|
||||
`UpdateUserId` int DEFAULT NULL,
|
||||
|
||||
8
sql/migrate_t_customer_account_flow_concurrency.sql
Normal file
8
sql/migrate_t_customer_account_flow_concurrency.sql
Normal file
@ -0,0 +1,8 @@
|
||||
-- 已执行旧版 migrate_t_customer_account_flow.sql 的库补 ConcurrencyStamp(与 AggregateRoot 实体对齐)
|
||||
-- 勿在 ALTER 中使用 DEFAULT(UUID()),复制环境会报 Error 1674
|
||||
ALTER TABLE `t_customer_account_flow`
|
||||
ADD COLUMN `ConcurrencyStamp` char(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
|
||||
|
||||
UPDATE `t_customer_account_flow`
|
||||
SET `ConcurrencyStamp` = UUID()
|
||||
WHERE `ConcurrencyStamp` = '';
|
||||
@ -0,0 +1,77 @@
|
||||
namespace Oms.Application.Dtos.Operations;
|
||||
|
||||
/// <summary>
|
||||
/// 出库扫描按单号查订单(只读展示销售产品、目的国、服务渠道)。
|
||||
/// </summary>
|
||||
public class OutboundOrderLookupOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 订单主键。
|
||||
/// </summary>
|
||||
public int OrderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务单号。
|
||||
/// </summary>
|
||||
public string ServiceNo { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 客户单号。
|
||||
/// </summary>
|
||||
public string? ClientNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跟踪号。
|
||||
/// </summary>
|
||||
public string? TrackNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 产品编码。
|
||||
/// </summary>
|
||||
public string? ProductCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 销售产品主键。
|
||||
/// </summary>
|
||||
public int? SalesProductId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 销售产品名称。
|
||||
/// </summary>
|
||||
public string? SalesProductName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 目的国家编码。
|
||||
/// </summary>
|
||||
public string? DestinationCountry { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 目的国家名称。
|
||||
/// </summary>
|
||||
public string? DestinationCountryName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务渠道主键。
|
||||
/// </summary>
|
||||
public int? ServiceChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务渠道编码。
|
||||
/// </summary>
|
||||
public string? ChannelCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务渠道展示名。
|
||||
/// </summary>
|
||||
public string? ServiceChannelName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单状态码。
|
||||
/// </summary>
|
||||
public string OrderStatus { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 订单状态名称。
|
||||
/// </summary>
|
||||
public string? OrderStatusName { get; set; }
|
||||
}
|
||||
@ -2,8 +2,12 @@ using Fake.Application;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Oms.Application.Dtos.Operations;
|
||||
using Oms.Application.Dtos.Shared;
|
||||
using Oms.Application.Shared;
|
||||
using Oms.Domain.ChannelsAggregate.Repositories;
|
||||
using Oms.Domain.OperationsAggregate.Entities;
|
||||
using Oms.Domain.OperationsAggregate.Repositories;
|
||||
using Oms.Domain.OrdersAggregate.Consts;
|
||||
using Oms.Domain.OrdersAggregate.Repositories;
|
||||
using Oms.Domain.SystemAggregate.Repositories;
|
||||
|
||||
namespace Oms.Application.Services.Operations;
|
||||
@ -15,7 +19,73 @@ namespace Oms.Application.Services.Operations;
|
||||
public class OutboundRecordService : ApplicationService
|
||||
{
|
||||
private IOutboundRecordRepository OutboundRecordRepository => LazyServiceProvider.GetRequiredService<IOutboundRecordRepository>();
|
||||
private IOrderRepository OrderRepository => LazyServiceProvider.GetRequiredService<IOrderRepository>();
|
||||
private ISalesProductRepository SalesProductRepository => LazyServiceProvider.GetRequiredService<ISalesProductRepository>();
|
||||
private IServiceChannelRepository ServiceChannelRepository => LazyServiceProvider.GetRequiredService<IServiceChannelRepository>();
|
||||
private IServiceChannelGroupRepository ServiceChannelGroupRepository => LazyServiceProvider.GetRequiredService<IServiceChannelGroupRepository>();
|
||||
private IWarehouseAddressRepository WarehouseAddressRepository => LazyServiceProvider.GetRequiredService<IWarehouseAddressRepository>();
|
||||
private ICountryRepository CountryRepository => LazyServiceProvider.GetRequiredService<ICountryRepository>();
|
||||
|
||||
/// <summary>
|
||||
/// 按单号查询订单(出库扫描展示销售产品、目的国、服务渠道,只读)。
|
||||
/// </summary>
|
||||
[HttpGet("/operation/outbound/order-lookup")]
|
||||
public async Task<OutboundOrderLookupOutput> LookupOrderAsync([FromQuery] string waybillNo)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(waybillNo))
|
||||
{
|
||||
throw new BusinessException("请扫描或输入单号");
|
||||
}
|
||||
|
||||
var order = await OrderRepository.GetByWaybillNoAsync(waybillNo.Trim());
|
||||
if (order == null)
|
||||
{
|
||||
throw new BusinessException("未找到对应订单,请检查单号");
|
||||
}
|
||||
|
||||
EnsureOutboundAllowed(order.OrderStatus);
|
||||
|
||||
var output = new OutboundOrderLookupOutput
|
||||
{
|
||||
OrderId = order.Id,
|
||||
ServiceNo = order.ServiceNo,
|
||||
ClientNo = order.ClientNo,
|
||||
TrackNo = order.TrackNo,
|
||||
ProductCode = order.ProductCode,
|
||||
DestinationCountry = order.ConsigneeCountry,
|
||||
OrderStatus = order.OrderStatus,
|
||||
OrderStatusName = OmsDocHelper.GetOrderStatusName(order.OrderStatus)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(order.ProductCode))
|
||||
{
|
||||
var product = await SalesProductRepository.GetByProductCodeAsync(order.ProductCode.Trim());
|
||||
if (product != null)
|
||||
{
|
||||
output.SalesProductId = product.Id;
|
||||
output.SalesProductName = product.ProductName;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(order.ConsigneeCountry))
|
||||
{
|
||||
var country = await CountryRepository.FirstOrDefaultAsync(x => x.CountryCode == order.ConsigneeCountry);
|
||||
output.DestinationCountryName = country?.ChineseName ?? country?.EnglishName ?? order.ConsigneeCountry;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(order.ChannelCode))
|
||||
{
|
||||
var channel = await ServiceChannelRepository.GetByChannelCodeAsync(order.ChannelCode.Trim());
|
||||
if (channel != null)
|
||||
{
|
||||
output.ServiceChannelId = channel.Id;
|
||||
output.ChannelCode = channel.ChannelCode;
|
||||
output.ServiceChannelName = await BuildServiceChannelDisplayNameAsync(channel.GroupId, channel.ChannelName);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增出库记录。
|
||||
@ -31,12 +101,25 @@ public class OutboundRecordService : ApplicationService
|
||||
[HttpPost("/operation/outbound/create")]
|
||||
public async Task<OutboundRecordOutput> CreateAsync(CreateOutboundRecordInput input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input.WaybillNo))
|
||||
{
|
||||
throw new BusinessException("运单号不能为空");
|
||||
}
|
||||
|
||||
var order = await OrderRepository.GetByWaybillNoAsync(input.WaybillNo.Trim());
|
||||
if (order == null)
|
||||
{
|
||||
throw new BusinessException("未找到对应订单,请检查单号");
|
||||
}
|
||||
|
||||
EnsureOutboundAllowed(order.OrderStatus);
|
||||
|
||||
var now = DateTime.Now;
|
||||
var operatorId = CurrentUser.GetId<int>();
|
||||
var entity = new OutboundRecord
|
||||
{
|
||||
WaybillNo = input.WaybillNo,
|
||||
WarehouseId = input.WarehouseId,
|
||||
WaybillNo = input.WaybillNo.Trim(),
|
||||
WarehouseId = input.WarehouseId ?? order.WarehouseId,
|
||||
OperateTime = now,
|
||||
OperatorId = operatorId
|
||||
};
|
||||
@ -86,4 +169,30 @@ public class OutboundRecordService : ApplicationService
|
||||
|
||||
return new OmsItemsResult<OutboundRecordOutput> { Items = items };
|
||||
}
|
||||
|
||||
private static void EnsureOutboundAllowed(string orderStatus)
|
||||
{
|
||||
if (orderStatus is OrderStatusCodes.PendingPayment or OrderStatusCodes.Received)
|
||||
{
|
||||
throw new BusinessException("订单未付款,禁止出库");
|
||||
}
|
||||
|
||||
if (orderStatus != OrderStatusCodes.PendingShip)
|
||||
{
|
||||
throw new BusinessException($"订单状态为「{OmsDocHelper.GetOrderStatusName(orderStatus)}」,不允许出库");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> BuildServiceChannelDisplayNameAsync(int? groupId, string channelName)
|
||||
{
|
||||
string? groupName = null;
|
||||
if (groupId.HasValue)
|
||||
{
|
||||
var group = await ServiceChannelGroupRepository.FirstOrDefaultAsync(x => x.Id == groupId.Value);
|
||||
groupName = group?.Name;
|
||||
}
|
||||
|
||||
var displayName = $"{groupName}{channelName}".Trim();
|
||||
return string.IsNullOrWhiteSpace(displayName) ? channelName : displayName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1142,7 +1142,7 @@ public partial class OrderService
|
||||
OrderFeeChargingStageCodes.Inbound,
|
||||
replaceExistingReceivable: true);
|
||||
|
||||
order.OrderStatus = OrderStatusCodes.Received;
|
||||
order.OrderStatus = OrderStatusCodes.PendingPayment;
|
||||
order.ReceiveTime = DateTime.Now;
|
||||
order.UpdateTime = DateTime.Now;
|
||||
await OrderRepository.UpdateAsync(order);
|
||||
|
||||
@ -119,7 +119,7 @@ public partial class OrderService : ApplicationService
|
||||
throw new BusinessException("订单已支付");
|
||||
}
|
||||
|
||||
if (order.OrderStatus != OrderStatusCodes.PendingPayment)
|
||||
if (order.OrderStatus is not (OrderStatusCodes.PendingPayment or OrderStatusCodes.Received))
|
||||
{
|
||||
throw new BusinessException("当前订单状态不可支付");
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user