Persist generated/printed/downstream labels in t_order_file, drop Order.LabelUrl generate-status fields, and expose file list/upload/delete APIs with customer read-only systemLabel access. Co-authored-by: Cursor <cursoragent@cursor.com>
566 lines
21 KiB
C#
566 lines
21 KiB
C#
using Fake.Application;
|
||
using Fake.Domain.Exceptions;
|
||
using Microsoft.AspNetCore.Hosting;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using MiniExcelLibs;
|
||
using Oms.Application.Dtos.Orders;
|
||
using Oms.Application.Dtos.Shared;
|
||
using Oms.Application.DataPerm;
|
||
using Oms.Application.Labeling;
|
||
using Oms.Application.Shared;
|
||
using Newtonsoft.Json;
|
||
using Oms.Application.Services.Orders.Batch;
|
||
using Oms.Domain.ChannelsAggregate.Repositories;
|
||
using Oms.Domain.CustomersAggregate.Repositories;
|
||
using Oms.Domain.OrdersAggregate;
|
||
using Oms.Domain.OrdersAggregate.Consts;
|
||
using Oms.Domain.OrdersAggregate.Entities;
|
||
using Oms.Domain.OrdersAggregate.Repositories;
|
||
using Oms.Domain.SystemAggregate.Entities;
|
||
using Oms.Domain.SystemAggregate.Repositories;
|
||
|
||
namespace Oms.Application.Services.Orders;
|
||
|
||
/// <summary>
|
||
/// 订单相关 API 服务。
|
||
/// </summary>
|
||
[ApiExplorerSettings(GroupName = "OMS-Order")]
|
||
public partial class OrderService : ApplicationService
|
||
{
|
||
private IOrderRepository OrderRepository => LazyServiceProvider.GetRequiredService<IOrderRepository>();
|
||
private IOrderTemplateRepository OrderTemplateRepository => LazyServiceProvider.GetRequiredService<IOrderTemplateRepository>();
|
||
private IWarehouseAddressRepository WarehouseAddressRepository => LazyServiceProvider.GetRequiredService<IWarehouseAddressRepository>();
|
||
private ISalesProductRepository SalesProductRepository => LazyServiceProvider.GetRequiredService<ISalesProductRepository>();
|
||
private IDictRepository DictRepository => LazyServiceProvider.GetRequiredService<IDictRepository>();
|
||
private IWebHostEnvironment WebHostEnvironment => LazyServiceProvider.GetRequiredService<IWebHostEnvironment>();
|
||
private LabelPdfGenerationService LabelPdfGenerationService =>
|
||
LazyServiceProvider.GetRequiredService<LabelPdfGenerationService>();
|
||
private OmsRbacUserDisplayNameResolver UserDisplayNameResolver =>
|
||
LazyServiceProvider.GetRequiredService<OmsRbacUserDisplayNameResolver>();
|
||
|
||
private EffectiveScopeBuilder DataScopeBuilder =>
|
||
LazyServiceProvider.GetRequiredService<EffectiveScopeBuilder>();
|
||
|
||
/// <summary>
|
||
/// 查询订单列表。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单分页查询条件。</param>
|
||
/// <returns>订单分页结果,包含列表数据和总记录数。</returns>
|
||
[HttpPost("/order/list")]
|
||
public async Task<OmsPageResult<OrderOutput>> GetPaginatedListAsync([FromBody] OrderPaginatedInput input)
|
||
{
|
||
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(
|
||
CustomerRepository,
|
||
CurrentUser,
|
||
input.CustomerId);
|
||
var filter = BuildListFilter(input, customerId);
|
||
await ApplyInternalOrderDataScopeAsync(filter);
|
||
var pageIndex = OmsDocHelper.NormalizePage(input.Page);
|
||
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
|
||
var (orders, total) = await OrderRepository.GetFilteredPagedListAsync(
|
||
pageIndex,
|
||
pageSize,
|
||
filter);
|
||
return new OmsPageResult<OrderOutput> { Items = await MapOrderOutputsAsync(orders), Total = total };
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按状态聚合统计订单数量(单次查询,供 Tab 角标展示)。
|
||
/// </summary>
|
||
[HttpGet("/order/status-counts")]
|
||
public async Task<OrderStatusCountsOutput> GetStatusCountsAsync()
|
||
{
|
||
var filter = await BuildScopedListFilterAsync();
|
||
var rows = await OrderRepository.GetStatusCountsByFilterAsync(filter);
|
||
var counts = rows.ToDictionary(
|
||
x => x.Status,
|
||
x => x.Count,
|
||
StringComparer.OrdinalIgnoreCase);
|
||
var handleRows = await OrderRepository.GetHandleStatusCountsByFilterAsync(filter);
|
||
var handleCounts = handleRows.ToDictionary(
|
||
x => x.Key,
|
||
x => new OrderHandleStatusCountsOutput
|
||
{
|
||
Pending = x.Value.Pending,
|
||
Processed = x.Value.Processed
|
||
},
|
||
StringComparer.OrdinalIgnoreCase);
|
||
return new OrderStatusCountsOutput
|
||
{
|
||
Total = rows.Sum(x => x.Count),
|
||
Counts = counts,
|
||
HandleCounts = handleCounts
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询订单详情。
|
||
/// </summary>
|
||
/// <param name="id">入参:目标主键。</param>
|
||
/// <returns>订单详情。</returns>
|
||
[HttpGet("/order/detail")]
|
||
public async Task<OrderOutput> GetDetailAsync([FromQuery] int id)
|
||
{
|
||
var order = await GetOrderOrThrowAsync(id);
|
||
return (await MapOrderOutputsAsync([order])).First();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行订单支付。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单操作参数。</param>
|
||
/// <returns>无返回体,仅完成订单支付处理。</returns>
|
||
[HttpPost("/order/pay")]
|
||
public async Task PayAsync(OrderActionInput input)
|
||
{
|
||
var order = await GetOrderOrThrowAsync(input.Id);
|
||
if (order.IsPaid > 0)
|
||
{
|
||
throw new BusinessException("订单已支付");
|
||
}
|
||
|
||
if (order.OrderStatus is not (OrderStatusCodes.PendingPayment or OrderStatusCodes.Received))
|
||
{
|
||
throw new BusinessException("当前订单状态不可支付");
|
||
}
|
||
|
||
if (!order.CustomerId.HasValue)
|
||
{
|
||
throw new BusinessException("订单未关联客户,无法支付");
|
||
}
|
||
|
||
var fees = await OrderRepository.GetFeesByOrderIdsAsync([order.Id]);
|
||
var payAmount = order.PayableAmount ?? fees
|
||
.Where(x => x.Type == OrderFeeTypeCodes.Receivable)
|
||
.Sum(x => x.Amount);
|
||
if (payAmount <= 0)
|
||
{
|
||
throw new BusinessException("订单应付金额无效,无法支付");
|
||
}
|
||
|
||
var customer = await CustomerRepository.FirstOrDefaultAsync(x => x.Id == order.CustomerId.Value);
|
||
if (customer == null)
|
||
{
|
||
throw new BusinessException("客户不存在");
|
||
}
|
||
|
||
var balanceMutator = LazyServiceProvider.GetRequiredService<CustomerBalanceMutator>();
|
||
await balanceMutator.DebitOrderPayAsync(
|
||
customer,
|
||
payAmount,
|
||
order.Id,
|
||
order.ServiceNo,
|
||
$"订单支付 {order.ServiceNo}");
|
||
|
||
if (order.CouponInstanceId.HasValue)
|
||
{
|
||
var couponManager = LazyServiceProvider.GetRequiredService<MarketingCouponManager>();
|
||
var mainCustomerId = await couponManager.ResolveMainCustomerIdAsync(customer.Id);
|
||
await couponManager.MarkUsedAsync(order.CouponInstanceId.Value, mainCustomerId, order.Id);
|
||
}
|
||
|
||
var mainCustomer = await MarketingCustomerHelper.ResolveMarketingMainCustomerAsync(CustomerRepository, customer);
|
||
var pointsManager = LazyServiceProvider.GetRequiredService<MarketingPointsManager>();
|
||
await pointsManager.EarnOnOrderPaidAsync(mainCustomer.Id, order.Id, payAmount);
|
||
|
||
order.PayTime = DateTime.Now;
|
||
order.IsPaid = 1;
|
||
order.OrderStatus = OrderStatusCodes.PendingShip;
|
||
await UpdateOrderAsync(order);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 标记订单派送成功(触发引荐分成 Pending)。
|
||
/// </summary>
|
||
[HttpPost("/order/mark-delivery-success")]
|
||
public async Task MarkDeliverySuccessAsync(OrderActionInput input)
|
||
{
|
||
var order = await GetOrderOrThrowAsync(input.Id);
|
||
order.OrderStatus = OrderStatusCodes.DeliverySuccess;
|
||
order.SignTime = DateTime.Now;
|
||
await UpdateOrderAsync(order);
|
||
|
||
var commissionManager = LazyServiceProvider.GetRequiredService<ReferralCommissionManager>();
|
||
await commissionManager.OnOrderDeliverySuccessAsync(order.Id);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行订单预报。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单操作参数。</param>
|
||
/// <returns>无返回体,仅完成订单预报处理。</returns>
|
||
[HttpPost("/order/pre-declare")]
|
||
public async Task PreDeclareAsync(OrderActionInput input)
|
||
{
|
||
var order = await GetOrderOrThrowAsync(input.Id);
|
||
order.OrderStatus = OrderStatusCodes.Predeclared;
|
||
await UpdateOrderAsync(order);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行订单拦截。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单操作参数。</param>
|
||
/// <returns>无返回体,仅完成订单拦截处理。</returns>
|
||
[HttpPost("/order/intercept")]
|
||
public async Task InterceptAsync(OrderActionInput input)
|
||
{
|
||
var order = await GetOrderOrThrowAsync(input.Id);
|
||
order.IsIntercept = 1;
|
||
await UpdateOrderAsync(order);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 取消订单拦截。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单操作参数。</param>
|
||
/// <returns>无返回体,仅完成取消订单拦截。</returns>
|
||
[HttpPost("/order/cancel-intercept")]
|
||
public async Task CancelInterceptAsync(OrderActionInput input)
|
||
{
|
||
var order = await GetOrderOrThrowAsync(input.Id);
|
||
order.IsIntercept = 0;
|
||
await UpdateOrderAsync(order);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除订单。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单操作参数。</param>
|
||
/// <returns>无返回体,仅完成删除订单。</returns>
|
||
[HttpPost("/order/delete")]
|
||
public async Task DeleteAsync(OrderActionInput input)
|
||
{
|
||
var order = await GetOrderOrThrowAsync(input.Id);
|
||
if (order.OrderStatus is not (OrderStatusCodes.Draft or OrderStatusCodes.Predeclared))
|
||
{
|
||
throw new BusinessException("仅草稿或已预报订单可删除");
|
||
}
|
||
|
||
order.OrderStatus = OrderStatusCodes.Deleted;
|
||
await OrderRepository.UpdateAsync(order);
|
||
await OrderRepository.DeleteAsync(order);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 打印订单。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单操作参数。</param>
|
||
/// <returns>订单打印结果。</returns>
|
||
[HttpPost("/order/print")]
|
||
public async Task<OrderPrintOutput> PrintAsync(OrderActionInput input)
|
||
{
|
||
var order = await GetOrderOrThrowAsync(input.Id);
|
||
var mapped = (await MapOrderOutputsAsync([order])).First();
|
||
|
||
var existingUrl = await OrderFileManager.GetSystemLabelUrlAsync(order.Id);
|
||
if (!string.IsNullOrWhiteSpace(existingUrl))
|
||
{
|
||
return new OrderPrintOutput
|
||
{
|
||
PrintUrl = existingUrl!,
|
||
LabelGenerateStatus = LabelGenerateStatusCodes.Ready
|
||
};
|
||
}
|
||
|
||
// 无系统面单:即时补生成(打印场景优先出 PDF)
|
||
var result = await LabelPdfGenerationService.GenerateAndPersistAsync(
|
||
order,
|
||
mapped,
|
||
templateIdOverride: null,
|
||
operatorName: CurrentUser.UserName,
|
||
operatorUserId: CurrentUser.IsAuthenticated ? CurrentUser.GetId<int>() : 0);
|
||
|
||
if (!result.Success || string.IsNullOrWhiteSpace(result.LabelUrl))
|
||
{
|
||
// 兼容回落:仍无模板时给 HTML stub,避免彻底不可打
|
||
var fallbackUrl = await CreateOrderPrintFileAsync(mapped);
|
||
return new OrderPrintOutput
|
||
{
|
||
PrintUrl = fallbackUrl,
|
||
LabelGenerateStatus = result.Status,
|
||
LabelGenerateError = result.Error ?? "面单 PDF 未就绪,已回落 HTML"
|
||
};
|
||
}
|
||
|
||
return new OrderPrintOutput
|
||
{
|
||
PrintUrl = result.LabelUrl!,
|
||
LabelGenerateStatus = result.Status,
|
||
LabelGenerateError = result.Error
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 导出订单。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单导出筛选条件。</param>
|
||
/// <returns>订单导出结果。</returns>
|
||
[HttpPost("/order/export")]
|
||
public async Task<OrderExportOutput> ExportAsync([FromBody] OrderExportInput input)
|
||
{
|
||
await CleanupExpiredFilesAsync(GetOrderExportDirectory());
|
||
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(
|
||
CustomerRepository,
|
||
CurrentUser,
|
||
null);
|
||
var filter = BuildListFilter(input, customerId);
|
||
await ApplyInternalOrderDataScopeAsync(filter);
|
||
var orders = await OrderRepository.GetFilteredListAsync(filter);
|
||
var fileName = $"orders-{DateTime.Now:yyyyMMddHHmmss}.xlsx";
|
||
var directory = GetOrderExportDirectory();
|
||
Directory.CreateDirectory(directory);
|
||
await MiniExcel.SaveAsAsync(Path.Combine(directory, fileName), await BuildOrderExportRowsAsync(orders));
|
||
return new OrderExportOutput
|
||
{
|
||
DownloadUrl = $"/uploads/exports/orders/{fileName}",
|
||
ExpireAt = DateTime.Now.AddHours(24)
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查价运输方式选项(按销售产品分组)。
|
||
/// </summary>
|
||
[HttpGet("/order/price-check/shipping-options")]
|
||
public Task<OrderPriceCheckShippingOptionsOutput> GetPriceCheckShippingOptionsAsync() =>
|
||
BuildPriceCheckShippingOptionsAsync();
|
||
|
||
/// <summary>
|
||
/// 执行订单运费试算。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单运费试算参数。</param>
|
||
/// <returns>订单运费试算列表结果。</returns>
|
||
[HttpPost("/order/price-check")]
|
||
public async Task<OrderPriceCheckResultOutput> PriceCheckAsync(OrderPriceCheckInput input)
|
||
{
|
||
if (!input.CustomerId.HasValue || input.CustomerId.Value <= 0)
|
||
{
|
||
input.CustomerId = await ResolvePriceCheckCustomerIdAsync();
|
||
}
|
||
|
||
return await BuildPriceCheckResultAsync(input);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询订单模板列表。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单模板列表查询条件。</param>
|
||
/// <returns>订单模板分页结果,包含列表数据和总记录数。</returns>
|
||
[HttpGet("/order/template/list")]
|
||
public async Task<OmsPageResult<OrderTemplateOutput>> GetTemplateListAsync([FromQuery] OrderTemplateListInput input)
|
||
{
|
||
var items = await GetTemplateOutputsAsync(input);
|
||
return items;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 下载订单模板文件。
|
||
/// </summary>
|
||
/// <param name="templateId">入参:模板主键。</param>
|
||
/// <returns>文件流响应。</returns>
|
||
[HttpGet("/order/template/download")]
|
||
public async Task<FileContentResult> DownloadTemplateAsync([FromQuery] int templateId)
|
||
{
|
||
return await BuildTemplateDownloadAsync(templateId);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 导入订单文件,创建 import-row 批量任务并返回 jobId。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单导入参数。</param>
|
||
/// <returns>批量任务 ID 及是否异步处理。</returns>
|
||
[HttpPost("/order/upload")]
|
||
public async Task<OrderUploadOutput> UploadAsync([FromForm] OrderUploadInput input)
|
||
{
|
||
return await ImportOrdersAsync(input);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建订单包裹。
|
||
/// </summary>
|
||
/// <param name="input">入参:订单包裹创建参数。</param>
|
||
/// <returns>订单包裹创建结果。</returns>
|
||
[HttpPost("/order/parcel/create")]
|
||
public async Task<OrderParcelCreateOutput> CreateParcelAsync(OrderParcelCreateInput input)
|
||
{
|
||
return await CreateParcelCoreAsync(input);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 批量创建订单包裹。
|
||
/// </summary>
|
||
/// <param name="input">入参:批量创建小包请求集合,每条记录沿用单票创建结构。</param>
|
||
/// <returns>批量处理结果,包含批次号、成功失败数量与逐条执行明细。</returns>
|
||
[HttpPost("/order/parcel/batch-create")]
|
||
public async Task<OrderParcelBatchCreateOutput> BatchCreateParcelAsync(OrderParcelBatchCreateInput input)
|
||
{
|
||
if (input == null || input.Count == 0)
|
||
{
|
||
throw new BusinessException("批量创建请求不能为空");
|
||
}
|
||
|
||
if (input.Count > ParcelBatchMaxCount)
|
||
{
|
||
throw new BusinessException($"单次批量创建不能超过{ParcelBatchMaxCount}条");
|
||
}
|
||
|
||
if (BatchJobPublisher.IsEnabled)
|
||
{
|
||
return await BatchCreateParcelViaQueueAsync(input);
|
||
}
|
||
|
||
return await BatchCreateParcelSyncAsync(input);
|
||
}
|
||
|
||
private async Task<OrderParcelBatchCreateOutput> BatchCreateParcelViaQueueAsync(OrderParcelBatchCreateInput input)
|
||
{
|
||
var batchNo = $"PCB{DateTime.Now:yyyyMMddHHmmssfff}";
|
||
var operatorUserId = CurrentUser.GetId<int>();
|
||
var payloadItems = input.Select((request, index) => new OrderBatchPayloadItemInput
|
||
{
|
||
OrderId = 0,
|
||
ServiceNo = request.ServiceNo,
|
||
ClientNo = request.ClientNo,
|
||
ItemKey = !string.IsNullOrWhiteSpace(request.RequestId)
|
||
? $"parcel:{request.RequestId}"
|
||
: $"parcel:{batchNo}:{index + 1}",
|
||
PayloadJson = JsonConvert.SerializeObject(request),
|
||
}).ToList();
|
||
|
||
var job = await BatchJobCoordinator.CreatePayloadJobAsync(
|
||
new OrderBatchPayloadJobCreateInput
|
||
{
|
||
Action = OrderBatchActionCodes.ParcelCreate,
|
||
RequestId = batchNo,
|
||
Items = payloadItems,
|
||
},
|
||
operatorUserId);
|
||
|
||
return new OrderParcelBatchCreateOutput
|
||
{
|
||
BatchNo = batchNo,
|
||
JobId = job.JobId,
|
||
Async = true,
|
||
Total = input.Count,
|
||
SuccessCount = 0,
|
||
FailCount = 0,
|
||
Items = [],
|
||
};
|
||
}
|
||
|
||
private async Task<OrderParcelBatchCreateOutput> BatchCreateParcelSyncAsync(OrderParcelBatchCreateInput input)
|
||
{
|
||
var batchNo = $"PCB{DateTime.Now:yyyyMMddHHmmssfff}";
|
||
var items = new List<OrderParcelBatchCreateItemOutput>(input.Count);
|
||
var successCount = 0;
|
||
|
||
for (var index = 0; index < input.Count; index++)
|
||
{
|
||
var request = input[index];
|
||
try
|
||
{
|
||
var output = await CreateParcelCoreAsync(request);
|
||
successCount++;
|
||
items.Add(new OrderParcelBatchCreateItemOutput
|
||
{
|
||
Index = index + 1,
|
||
RequestId = request.RequestId,
|
||
ClientNo = output.ClientNo ?? request.ClientNo,
|
||
ServiceNo = output.ServiceNo ?? request.ServiceNo,
|
||
TrackNo = output.TrackNo ?? request.TrackNo,
|
||
LabelUrl = output.LabelUrl,
|
||
Success = true,
|
||
Message = "success"
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
items.Add(new OrderParcelBatchCreateItemOutput
|
||
{
|
||
Index = index + 1,
|
||
RequestId = request.RequestId,
|
||
ClientNo = request.ClientNo,
|
||
ServiceNo = request.ServiceNo,
|
||
TrackNo = request.TrackNo,
|
||
Success = false,
|
||
Message = ex.Message
|
||
});
|
||
}
|
||
}
|
||
|
||
return new OrderParcelBatchCreateOutput
|
||
{
|
||
BatchNo = batchNo,
|
||
SuccessCount = successCount,
|
||
FailCount = items.Count - successCount,
|
||
Items = items
|
||
};
|
||
}
|
||
|
||
private static OrderListFilter BuildListFilter(OrderPaginatedInput input, int? customerId) =>
|
||
new()
|
||
{
|
||
Status = input.Status,
|
||
HandleStatus = input.HandleStatus,
|
||
OrderSource = input.OrderSource,
|
||
Keyword = input.Keyword,
|
||
CreateTimeStart = input.CreateTimeStart,
|
||
CreateTimeEnd = input.CreateTimeEnd,
|
||
CustomerId = customerId
|
||
};
|
||
|
||
private static OrderListFilter BuildListFilter(OrderExportInput input, int? customerId) =>
|
||
new()
|
||
{
|
||
Status = input.Status,
|
||
OrderSource = input.OrderSource,
|
||
Keyword = input.Keyword,
|
||
CreateTimeStart = input.CreateTimeStart,
|
||
CreateTimeEnd = input.CreateTimeEnd,
|
||
CustomerId = customerId
|
||
};
|
||
|
||
private async Task EnsureCustomerCanAccessOrderAsync(Order order)
|
||
{
|
||
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(
|
||
CustomerRepository,
|
||
CurrentUser,
|
||
null);
|
||
if (!customerId.HasValue)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (order.CustomerId == customerId.Value)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 兼容历史脏数据:下单人是当前客户账号,但订单 CustomerId 未写对
|
||
var mapId = OmsSessionHelper.TryGetCustomerMapId(CurrentUser);
|
||
if (mapId is > 0 && order.CreateUserId == mapId.Value)
|
||
{
|
||
return;
|
||
}
|
||
|
||
throw new BusinessException("订单不存在");
|
||
}
|
||
|
||
private async Task<Order> GetOrderOrThrowAsync(int id)
|
||
{
|
||
var entity = await OrderRepository.FirstOrDefaultAsync(x => x.Id == id);
|
||
if (entity == null)
|
||
{
|
||
throw new BusinessException("订单不存在");
|
||
}
|
||
|
||
await EnsureCustomerCanAccessOrderAsync(entity);
|
||
return entity;
|
||
}
|
||
|
||
private async Task UpdateOrderAsync(Order entity)
|
||
{
|
||
await OrderRepository.UpdateAsync(entity);
|
||
}
|
||
}
|