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();
|
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)
|
private async Task RecalculateReceivableCoreAsync(Order order)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(order.ProductCode))
|
if (string.IsNullOrWhiteSpace(order.ProductCode))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user