feat(order): 支持订单详情手动添加费用项
新增 OrderFeeAddInput 并在 OrderEdit 服务中实现费用追加逻辑,配合前端订单详情抽屉添加费用能力。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
74151b0738
commit
dd5c82e523
66
src/Oms.Application/Dtos/Orders/OrderFeeAddInput.cs
Normal file
66
src/Oms.Application/Dtos/Orders/OrderFeeAddInput.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Oms.Application.Dtos.Orders;
|
||||
|
||||
/// <summary>
|
||||
/// 手动添加订单费用入参。
|
||||
/// </summary>
|
||||
public class OrderFeeAddInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 订单主键。
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 费用类型:receivable / payable。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(16)]
|
||||
public string Type { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 费用项编码。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(64)]
|
||||
public string CostItem { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 金额。
|
||||
/// </summary>
|
||||
[Required]
|
||||
public decimal Amount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 币种。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(16)]
|
||||
public string Currency { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 计费阶段:forecast / inbound / outbound。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(16)]
|
||||
public string ChargingStage { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 下游服务商(应付可选)。
|
||||
/// </summary>
|
||||
[StringLength(128)]
|
||||
public string? DownstreamProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 价格编号(可选)。
|
||||
/// </summary>
|
||||
[StringLength(64)]
|
||||
public string? PriceNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 价格生效时间(可选)。
|
||||
/// </summary>
|
||||
public DateTime? PriceEffectiveTime { get; set; }
|
||||
}
|
||||
@ -233,6 +233,69 @@ public partial class OrderService
|
||||
return (await MapOrderOutputsAsync([order])).First();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动添加订单费用(应收或应付)。
|
||||
/// </summary>
|
||||
[HttpPost("/order/fee/add")]
|
||||
public async Task<OrderOutput> AddOrderFeeAsync(OrderFeeAddInput input)
|
||||
{
|
||||
var order = await GetOrderOrThrowAsync(input.Id);
|
||||
|
||||
var type = input.Type?.Trim().ToLowerInvariant() ?? string.Empty;
|
||||
if (type is not (OrderFeeTypeCodes.Receivable or OrderFeeTypeCodes.Payable))
|
||||
{
|
||||
throw new BusinessException("费用类型无效");
|
||||
}
|
||||
|
||||
var costItem = input.CostItem?.Trim() ?? string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(costItem))
|
||||
{
|
||||
throw new BusinessException("费用项不能为空");
|
||||
}
|
||||
|
||||
if (input.Amount <= 0)
|
||||
{
|
||||
throw new BusinessException("金额必须大于0");
|
||||
}
|
||||
|
||||
var currency = input.Currency?.Trim() ?? string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(currency))
|
||||
{
|
||||
throw new BusinessException("币种不能为空");
|
||||
}
|
||||
|
||||
var chargingStage = input.ChargingStage?.Trim() ?? string.Empty;
|
||||
if (chargingStage is not (
|
||||
OrderFeeChargingStageCodes.Forecast
|
||||
or OrderFeeChargingStageCodes.Inbound
|
||||
or OrderFeeChargingStageCodes.Outbound))
|
||||
{
|
||||
throw new BusinessException("计费阶段无效");
|
||||
}
|
||||
|
||||
var fee = new OrderFee
|
||||
{
|
||||
Type = type,
|
||||
CostItem = costItem,
|
||||
Amount = input.Amount,
|
||||
Currency = currency,
|
||||
ChargingStage = chargingStage,
|
||||
DownstreamProvider = string.IsNullOrWhiteSpace(input.DownstreamProvider)
|
||||
? null
|
||||
: input.DownstreamProvider.Trim(),
|
||||
PriceNo = string.IsNullOrWhiteSpace(input.PriceNo) ? null : input.PriceNo.Trim(),
|
||||
PriceEffectiveTime = input.PriceEffectiveTime,
|
||||
CreateTime = DateTime.Now,
|
||||
UpdateTime = DateTime.Now,
|
||||
};
|
||||
|
||||
await OrderRepository.UpsertFeesAsync(order.Id, [fee]);
|
||||
order.UpdateTime = DateTime.Now;
|
||||
await OrderRepository.UpdateAsync(order);
|
||||
|
||||
return (await MapOrderOutputsAsync([order])).First();
|
||||
}
|
||||
|
||||
private async Task RecalculateReceivableCoreAsync(Order order)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(order.ProductCode))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user