diff --git a/db.sql b/db.sql
index 3b2a822..ca9a7d5 100644
--- a/db.sql
+++ b/db.sql
@@ -133,6 +133,9 @@ CREATE TABLE `t_order` (
`PreviousOrderStatus` VARCHAR(32) NULL COMMENT '进入异常状态前的订单状态',
`WarehouseId` INT NULL COMMENT '仓库ID',
`CustomerId` INT NULL COMMENT '客户ID',
+ `OrderSource` VARCHAR(32) NULL COMMENT '订单来源:manual/pickup/upload/batch/platform',
+ `PickupTime` DATETIME NULL COMMENT '预约揽收时间',
+ `CustomerSenderAddressId` INT NULL COMMENT '发件地址簿 Id',
`OrganizationId` CHAR(36) NULL COMMENT '数据归属组织',
`SecretLevel` TINYINT NOT NULL DEFAULT 2 COMMENT '数据密级 1-4',
`SenderId` INT NULL COMMENT '发件人ID',
@@ -168,9 +171,39 @@ CREATE TABLE `t_order` (
KEY `idx_ord_sender` (`SenderId`),
KEY `idx_ord_recipient` (`RecipientId`),
KEY `idx_ord_declaration` (`DeclarationId`),
- KEY `idx_ord_org_secret_ctime` (`OrganizationId`, `SecretLevel`, `CreateTime`)
+ KEY `idx_ord_org_secret_ctime` (`OrganizationId`, `SecretLevel`, `CreateTime`),
+ KEY `idx_ord_source_ctime` (`OrderSource`, `CreateTime`)
) COMMENT='订单表';
+CREATE TABLE `t_customer_sender_address` (
+ `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `CustomerId` INT NOT NULL COMMENT '归属客户 t_customer.Id',
+ `AddressName` VARCHAR(64) NULL COMMENT '地址别名',
+ `SenderName` VARCHAR(50) NOT NULL COMMENT '发件人姓名',
+ `Company` VARCHAR(255) NULL COMMENT '公司',
+ `Country` INT NULL COMMENT '国家 t_country.Id',
+ `Province` VARCHAR(50) NULL COMMENT '州省',
+ `City` VARCHAR(50) NULL COMMENT '城市',
+ `ZipCode` VARCHAR(50) NULL COMMENT '邮编',
+ `StreetAddress1` VARCHAR(500) NOT NULL COMMENT '地址1',
+ `StreetAddress2` VARCHAR(500) NULL COMMENT '地址2',
+ `StreetAddress3` VARCHAR(500) NULL COMMENT '地址3',
+ `HouseNumber` VARCHAR(50) NULL COMMENT '门牌号',
+ `Phone` VARCHAR(50) NULL COMMENT '手机',
+ `TelePhone` VARCHAR(50) NULL COMMENT '电话',
+ `Email` VARCHAR(60) NULL COMMENT '邮箱',
+ `IsDefault` TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认:0-否,1-是',
+ `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
+ `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
+ `CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
+ `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `UpdateUserId` INT NULL COMMENT '更新人',
+ `UpdateTime` DATETIME NULL COMMENT '更新时间',
+ PRIMARY KEY (`Id`),
+ KEY `idx_csa_customer` (`CustomerId`, `IsDeleted`, `Id`),
+ KEY `idx_csa_customer_default` (`CustomerId`, `IsDefault`)
+) COMMENT='客户发件地址簿';
+
CREATE TABLE `t_order_template` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,步长 1',
`Name` VARCHAR(64) NOT NULL COMMENT '模板名称',
diff --git a/sql/migrate_t_customer_sender_address.sql b/sql/migrate_t_customer_sender_address.sql
new file mode 100644
index 0000000..d3815a7
--- /dev/null
+++ b/sql/migrate_t_customer_sender_address.sql
@@ -0,0 +1,32 @@
+-- 已有库增量:客户发件地址簿 t_customer_sender_address
+-- 对应功能:客户 → 发件地址;揽收订单选址;见 oms系统设计-050801.md §4.2.10
+-- 可重复执行(IF NOT EXISTS)
+
+CREATE TABLE IF NOT EXISTS `t_customer_sender_address` (
+ `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `CustomerId` INT NOT NULL COMMENT '归属客户 t_customer.Id',
+ `AddressName` VARCHAR(64) NULL COMMENT '地址别名',
+ `SenderName` VARCHAR(50) NOT NULL COMMENT '发件人姓名',
+ `Company` VARCHAR(255) NULL COMMENT '公司',
+ `Country` INT NULL COMMENT '国家 t_country.Id',
+ `Province` VARCHAR(50) NULL COMMENT '州省',
+ `City` VARCHAR(50) NULL COMMENT '城市',
+ `ZipCode` VARCHAR(50) NULL COMMENT '邮编',
+ `StreetAddress1` VARCHAR(500) NOT NULL COMMENT '地址1',
+ `StreetAddress2` VARCHAR(500) NULL COMMENT '地址2',
+ `StreetAddress3` VARCHAR(500) NULL COMMENT '地址3',
+ `HouseNumber` VARCHAR(50) NULL COMMENT '门牌号',
+ `Phone` VARCHAR(50) NULL COMMENT '手机',
+ `TelePhone` VARCHAR(50) NULL COMMENT '电话',
+ `Email` VARCHAR(60) NULL COMMENT '邮箱',
+ `IsDefault` TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认:0-否,1-是',
+ `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
+ `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
+ `CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
+ `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `UpdateUserId` INT NULL COMMENT '更新人',
+ `UpdateTime` DATETIME NULL COMMENT '更新时间',
+ PRIMARY KEY (`Id`),
+ KEY `idx_csa_customer` (`CustomerId`, `IsDeleted`, `Id`),
+ KEY `idx_csa_customer_default` (`CustomerId`, `IsDefault`)
+) COMMENT='客户发件地址簿';
diff --git a/sql/migrate_t_order_pickup_fields.sql b/sql/migrate_t_order_pickup_fields.sql
new file mode 100644
index 0000000..896b0d2
--- /dev/null
+++ b/sql/migrate_t_order_pickup_fields.sql
@@ -0,0 +1,75 @@
+-- 已有库增量:t_order 揽收订单字段 OrderSource / PickupTime / CustomerSenderAddressId
+-- 对应功能:订单 → 揽收订单;见 oms系统设计-050801.md §4.2.1 / §4.4.4
+-- 可重复执行
+
+SET @col_exists := (
+ SELECT COUNT(1)
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 't_order'
+ AND COLUMN_NAME = 'OrderSource'
+);
+
+SET @sql := IF(
+ @col_exists = 0,
+ 'ALTER TABLE `t_order` ADD COLUMN `OrderSource` VARCHAR(32) NULL COMMENT ''订单来源:manual/pickup/upload/batch/platform'' AFTER `CustomerId`',
+ 'SELECT ''t_order.OrderSource already exists'' AS info'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+SET @col_exists := (
+ SELECT COUNT(1)
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 't_order'
+ AND COLUMN_NAME = 'PickupTime'
+);
+
+SET @sql := IF(
+ @col_exists = 0,
+ 'ALTER TABLE `t_order` ADD COLUMN `PickupTime` DATETIME NULL COMMENT ''预约揽收时间'' AFTER `OrderSource`',
+ 'SELECT ''t_order.PickupTime already exists'' AS info'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+SET @col_exists := (
+ SELECT COUNT(1)
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 't_order'
+ AND COLUMN_NAME = 'CustomerSenderAddressId'
+);
+
+SET @sql := IF(
+ @col_exists = 0,
+ 'ALTER TABLE `t_order` ADD COLUMN `CustomerSenderAddressId` INT NULL COMMENT ''发件地址簿 Id'' AFTER `PickupTime`',
+ 'SELECT ''t_order.CustomerSenderAddressId already exists'' AS info'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+UPDATE `t_order`
+SET `OrderSource` = 'manual'
+WHERE `OrderSource` IS NULL OR `OrderSource` = '';
+
+SET @idx_exists := (
+ SELECT COUNT(1)
+ FROM information_schema.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 't_order'
+ AND INDEX_NAME = 'idx_ord_source_ctime'
+);
+
+SET @sql := IF(
+ @idx_exists = 0,
+ 'ALTER TABLE `t_order` ADD KEY `idx_ord_source_ctime` (`OrderSource`, `CreateTime`)',
+ 'SELECT ''idx_ord_source_ctime already exists'' AS info'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
diff --git a/src/Oms.Application/Dtos/Orders/CustomerSenderAddressDtos.cs b/src/Oms.Application/Dtos/Orders/CustomerSenderAddressDtos.cs
new file mode 100644
index 0000000..f01632f
--- /dev/null
+++ b/src/Oms.Application/Dtos/Orders/CustomerSenderAddressDtos.cs
@@ -0,0 +1,159 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Oms.Application.Dtos.Orders;
+
+///
+/// 客户发件地址分页查询。
+///
+public class CustomerSenderAddressPaginatedInput
+{
+ [Newtonsoft.Json.JsonProperty("page")]
+ public int Page { get; set; } = 1;
+
+ [Newtonsoft.Json.JsonProperty("pageSize")]
+ public int PageSize { get; set; } = 30;
+
+ [Newtonsoft.Json.JsonProperty("keyword")]
+ public string? Keyword { get; set; }
+
+ [Newtonsoft.Json.JsonProperty("onlyDefault")]
+ public bool OnlyDefault { get; set; }
+}
+
+///
+/// 新增发件地址。
+///
+public class CreateCustomerSenderAddressInput
+{
+ [StringLength(64)]
+ public string? AddressName { get; set; }
+
+ [Required]
+ [StringLength(50)]
+ public string SenderName { get; set; } = string.Empty;
+
+ [StringLength(255)]
+ public string? Company { get; set; }
+
+ [StringLength(8)]
+ public string? CountryCode { get; set; }
+
+ [StringLength(50)]
+ public string? Province { get; set; }
+
+ [StringLength(50)]
+ public string? City { get; set; }
+
+ [StringLength(50)]
+ public string? ZipCode { get; set; }
+
+ [Required]
+ [StringLength(500)]
+ public string StreetAddress1 { get; set; } = string.Empty;
+
+ [StringLength(500)]
+ public string? StreetAddress2 { get; set; }
+
+ [StringLength(500)]
+ public string? StreetAddress3 { get; set; }
+
+ [StringLength(50)]
+ public string? HouseNumber { get; set; }
+
+ [StringLength(50)]
+ public string? Phone { get; set; }
+
+ [StringLength(50)]
+ public string? TelePhone { get; set; }
+
+ [StringLength(60)]
+ public string? Email { get; set; }
+
+ public bool IsDefault { get; set; }
+}
+
+///
+/// 更新发件地址。
+///
+public class UpdateCustomerSenderAddressInput : CreateCustomerSenderAddressInput
+{
+ [Required]
+ public int Id { get; set; }
+}
+
+///
+/// 发件地址出参。
+///
+public class CustomerSenderAddressOutput
+{
+ public int Id { get; set; }
+
+ public int CustomerId { get; set; }
+
+ public string? AddressName { get; set; }
+
+ public string SenderName { get; set; } = string.Empty;
+
+ public string? Company { get; set; }
+
+ public int? Country { get; set; }
+
+ public string? CountryCode { get; set; }
+
+ public string? Province { get; set; }
+
+ public string? City { get; set; }
+
+ public string? ZipCode { get; set; }
+
+ public string StreetAddress1 { get; set; } = string.Empty;
+
+ public string? StreetAddress2 { get; set; }
+
+ public string? StreetAddress3 { get; set; }
+
+ public string? HouseNumber { get; set; }
+
+ public string? Phone { get; set; }
+
+ public string? TelePhone { get; set; }
+
+ public string? Email { get; set; }
+
+ public bool IsDefault { get; set; }
+
+ public DateTime? CreateTime { get; set; }
+
+ public DateTime? UpdateTime { get; set; }
+}
+
+///
+/// 创建揽收订单入参。
+///
+public class OrderPickupCreateInput
+{
+ public string? RequestId { get; set; }
+
+ public string? ClientNo { get; set; }
+
+ [Required]
+ public string ProductCode { get; set; } = string.Empty;
+
+ [Required]
+ public int WarehouseId { get; set; }
+
+ [Required]
+ public int SenderAddressId { get; set; }
+
+ [Required]
+ public DateTime PickupTime { get; set; }
+
+ [Required]
+ [StringLength(200)]
+ public string CargoName { get; set; } = string.Empty;
+
+ [Required]
+ public decimal ActualWeight { get; set; }
+
+ public string? CargoAttribute { get; set; }
+}
diff --git a/src/Oms.Application/Dtos/Orders/OrderExportInput.cs b/src/Oms.Application/Dtos/Orders/OrderExportInput.cs
index 1b757f4..6d8e8e8 100644
--- a/src/Oms.Application/Dtos/Orders/OrderExportInput.cs
+++ b/src/Oms.Application/Dtos/Orders/OrderExportInput.cs
@@ -11,6 +11,12 @@ public class OrderExportInput
[Newtonsoft.Json.JsonProperty("status")]
public string? Status { get; set; }
+ ///
+ /// 订单来源:all / manual / pickup 等。
+ ///
+ [Newtonsoft.Json.JsonProperty("orderSource")]
+ public string? OrderSource { get; set; }
+
///
/// 关键词。
///
diff --git a/src/Oms.Application/Dtos/Orders/OrderOutput.cs b/src/Oms.Application/Dtos/Orders/OrderOutput.cs
index 2d45a04..6e375d6 100644
--- a/src/Oms.Application/Dtos/Orders/OrderOutput.cs
+++ b/src/Oms.Application/Dtos/Orders/OrderOutput.cs
@@ -95,6 +95,21 @@ public class OrderOutput
///
public int? CustomerId { get; set; }
+ ///
+ /// 订单来源。
+ ///
+ public string? OrderSource { get; set; }
+
+ ///
+ /// 预约揽收时间。
+ ///
+ public DateTime? PickupTime { get; set; }
+
+ ///
+ /// 发件地址簿 Id。
+ ///
+ public int? CustomerSenderAddressId { get; set; }
+
///
/// 幂等请求标识。
///
diff --git a/src/Oms.Application/Dtos/Orders/OrderPaginatedInput.cs b/src/Oms.Application/Dtos/Orders/OrderPaginatedInput.cs
index a2075d6..eaf3cf0 100644
--- a/src/Oms.Application/Dtos/Orders/OrderPaginatedInput.cs
+++ b/src/Oms.Application/Dtos/Orders/OrderPaginatedInput.cs
@@ -31,6 +31,13 @@ public class OrderPaginatedInput
[global::System.Text.Json.Serialization.JsonPropertyName("handleStatus")]
public string? HandleStatus { get; set; }
+ ///
+ /// 订单来源:all / manual / pickup / upload / batch / platform。
+ ///
+ [Newtonsoft.Json.JsonProperty("orderSource")]
+ [global::System.Text.Json.Serialization.JsonPropertyName("orderSource")]
+ public string? OrderSource { get; set; }
+
///
/// 关键词。
///
diff --git a/src/Oms.Application/Services/Orders/OrderService.Helpers.cs b/src/Oms.Application/Services/Orders/OrderService.Helpers.cs
index 53161ac..bf023c5 100644
--- a/src/Oms.Application/Services/Orders/OrderService.Helpers.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.Helpers.cs
@@ -119,6 +119,11 @@ public partial class OrderService
? warehouse.WarehouseName
: null,
CustomerId = order.CustomerId,
+ OrderSource = string.IsNullOrWhiteSpace(order.OrderSource)
+ ? OrderSourceCodes.Manual
+ : order.OrderSource,
+ PickupTime = order.PickupTime,
+ CustomerSenderAddressId = order.CustomerSenderAddressId,
RequestId = order.RequestId,
ExportCustomsMode = order.ExportCustomsMode,
PredeclareFailReason = string.IsNullOrWhiteSpace(order.PredeclareFailReason)
diff --git a/src/Oms.Application/Services/Orders/OrderService.Monitor.cs b/src/Oms.Application/Services/Orders/OrderService.Monitor.cs
index 6e8396d..dcad38a 100644
--- a/src/Oms.Application/Services/Orders/OrderService.Monitor.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.Monitor.cs
@@ -276,6 +276,8 @@ public partial class OrderService
return new OrderListFilter
{
Status = filter.Status,
+ HandleStatus = filter.HandleStatus,
+ OrderSource = filter.OrderSource,
Keyword = filter.Keyword,
CreateTimeStart = start,
CreateTimeEnd = filter.CreateTimeEnd,
diff --git a/src/Oms.Application/Services/Orders/OrderService.ParcelBilling.cs b/src/Oms.Application/Services/Orders/OrderService.ParcelBilling.cs
index 03f09d4..fd3320a 100644
--- a/src/Oms.Application/Services/Orders/OrderService.ParcelBilling.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.ParcelBilling.cs
@@ -40,9 +40,19 @@ public partial class OrderService
private OrderAutoTriggerService OrderAutoTriggerService =>
LazyServiceProvider.GetRequiredService();
+ private sealed class ParcelCreateContext
+ {
+ public string? OrderSource { get; init; }
+
+ public DateTime? PickupTime { get; init; }
+
+ public int? CustomerSenderAddressId { get; init; }
+ }
+
private async Task CreateParcelCoreAsync(
OrderParcelCreateInput input,
- int? operatorUserId = null)
+ int? operatorUserId = null,
+ ParcelCreateContext? createContext = null)
{
if (!string.IsNullOrWhiteSpace(input.RequestId))
{
@@ -88,7 +98,14 @@ public partial class OrderService
country.ChineseName);
var serviceNo = await ResolveServiceNoAsync();
- var order = BuildDraftOrderEntity(input, product, country.CountryCode, country.ChineseName, snapshotBinding, serviceNo);
+ var order = BuildDraftOrderEntity(
+ input,
+ product,
+ country.CountryCode,
+ country.ChineseName,
+ snapshotBinding,
+ serviceNo,
+ createContext);
order = await OrderRepository.InsertAsync(order);
var weights = BuildInitialWeightRows(order.Id, input);
@@ -1076,8 +1093,13 @@ public partial class OrderService
string consigneeCountry,
string consigneeCountryName,
ProductSnapshotBinding snapshotBinding,
- string serviceNo)
+ string serviceNo,
+ ParcelCreateContext? createContext = null)
{
+ var orderSource = string.IsNullOrWhiteSpace(createContext?.OrderSource)
+ ? OrderSourceCodes.Manual
+ : createContext!.OrderSource!.Trim();
+
return new Order
{
RequestId = input.RequestId,
@@ -1092,6 +1114,9 @@ public partial class OrderService
ExportCustomsMode = input.ExportCustomsMode,
WarehouseId = input.WarehouseId,
CustomerId = input.CustomerId,
+ OrderSource = orderSource,
+ PickupTime = createContext?.PickupTime,
+ CustomerSenderAddressId = createContext?.CustomerSenderAddressId,
IsCod = input.IsCod ? (byte)1 : (byte)0,
CodCurrency = input.CodCurrency,
CodSum = input.CodSum,
diff --git a/src/Oms.Application/Services/Orders/OrderService.Pickup.cs b/src/Oms.Application/Services/Orders/OrderService.Pickup.cs
new file mode 100644
index 0000000..e37a354
--- /dev/null
+++ b/src/Oms.Application/Services/Orders/OrderService.Pickup.cs
@@ -0,0 +1,84 @@
+using Fake.Application;
+using Microsoft.AspNetCore.Mvc;
+using Oms.Application.Dtos.Orders;
+using Oms.Application.Shared;
+using Oms.Domain.OrdersAggregate.Consts;
+using Oms.Domain.SystemAggregate.Entities;
+
+namespace Oms.Application.Services.Orders;
+
+public partial class OrderService
+{
+ ///
+ /// 创建揽收订单(组装小包入参后复用创建核心)。
+ ///
+ [HttpPost("/order/pickup/create")]
+ public async Task CreatePickupOrderAsync([FromBody] OrderPickupCreateInput input)
+ {
+ if (input.WarehouseId <= 0)
+ {
+ throw new BusinessException("仓库ID不能为空");
+ }
+
+ if (input.SenderAddressId <= 0)
+ {
+ throw new BusinessException("发件地址不能为空");
+ }
+
+ if (string.IsNullOrWhiteSpace(input.ProductCode))
+ {
+ throw new BusinessException("运输方式不能为空");
+ }
+
+ if (string.IsNullOrWhiteSpace(input.CargoName))
+ {
+ throw new BusinessException("货物名称不能为空");
+ }
+
+ if (input.ActualWeight <= 0)
+ {
+ throw new BusinessException("货物重量必须大于0");
+ }
+
+ if (input.PickupTime == default)
+ {
+ throw new BusinessException("揽收时间不能为空");
+ }
+
+ var customer = await OmsSessionHelper.ResolveSessionCustomerAsync(CustomerRepository, CurrentUser);
+ var senderAddress = await CustomerSenderAddressRepository.GetOwnedAsync(input.SenderAddressId, customer.Id);
+ if (senderAddress == null)
+ {
+ throw new BusinessException("发件地址不存在");
+ }
+
+ var warehouse = await WarehouseAddressRepository.FirstOrDefaultAsync(x => x.Id == input.WarehouseId);
+ if (warehouse == null)
+ {
+ throw new BusinessException("仓库不存在");
+ }
+
+ string? senderCountryCode = null;
+ if (senderAddress.Country.HasValue)
+ {
+ var country = await CountryRepository.FirstOrDefaultAsync(x => x.Id == senderAddress.Country.Value);
+ senderCountryCode = country?.CountryCode;
+ }
+
+ var parcelInput = PickupOrderParcelBuilder.Build(
+ input,
+ senderAddress,
+ warehouse,
+ customer.Id,
+ senderCountryCode);
+
+ return await CreateParcelCoreAsync(
+ parcelInput,
+ createContext: new ParcelCreateContext
+ {
+ OrderSource = OrderSourceCodes.Pickup,
+ PickupTime = input.PickupTime,
+ CustomerSenderAddressId = senderAddress.Id
+ });
+ }
+}
diff --git a/src/Oms.Application/Services/Orders/OrderService.SenderAddress.cs b/src/Oms.Application/Services/Orders/OrderService.SenderAddress.cs
new file mode 100644
index 0000000..8f71ce8
--- /dev/null
+++ b/src/Oms.Application/Services/Orders/OrderService.SenderAddress.cs
@@ -0,0 +1,253 @@
+using System.Linq.Expressions;
+using Fake.Application;
+using Microsoft.AspNetCore.Mvc;
+using Oms.Application.Dtos.Orders;
+using Oms.Application.Dtos.Shared;
+using Oms.Application.Shared;
+using Oms.Domain.OrdersAggregate.Entities;
+using Oms.Domain.OrdersAggregate.Repositories;
+
+namespace Oms.Application.Services.Orders;
+
+public partial class OrderService
+{
+ private ICustomerSenderAddressRepository CustomerSenderAddressRepository =>
+ LazyServiceProvider.GetRequiredService();
+
+ ///
+ /// 发件地址分页列表。
+ ///
+ [HttpPost("/order/sender-address/list")]
+ public async Task> GetSenderAddressListAsync(
+ [FromBody] CustomerSenderAddressPaginatedInput input)
+ {
+ var customer = await OmsSessionHelper.ResolveSessionCustomerAsync(CustomerRepository, CurrentUser);
+ var pageIndex = OmsDocHelper.NormalizePage(input.Page);
+ var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
+ var predicate = BuildSenderAddressPredicate(customer.Id, input);
+
+ var entities = await CustomerSenderAddressRepository.GetPagedListAsync(
+ predicate,
+ pageIndex,
+ pageSize,
+ new Dictionary
+ {
+ [nameof(CustomerSenderAddress.IsDefault)] = false,
+ [nameof(CustomerSenderAddress.Id)] = false
+ });
+ var total = await CustomerSenderAddressRepository.CountAsync(predicate);
+ var countryMap = await LoadCountryCodeMapAsync(entities.Select(x => x.Country).Where(x => x.HasValue).Select(x => x!.Value));
+
+ return new OmsPageResult
+ {
+ Items = entities.Select(x => MapSenderAddressOutput(x, countryMap)).ToList(),
+ Total = total
+ };
+ }
+
+ ///
+ /// 发件地址详情。
+ ///
+ [HttpGet("/order/sender-address/detail")]
+ public async Task GetSenderAddressDetailAsync([FromQuery] int id)
+ {
+ var entity = await GetOwnedSenderAddressOrThrowAsync(id);
+ var countryMap = await LoadCountryCodeMapAsync(entity.Country.HasValue ? [entity.Country.Value] : []);
+ return MapSenderAddressOutput(entity, countryMap);
+ }
+
+ ///
+ /// 新增发件地址。
+ ///
+ [HttpPost("/order/sender-address/create")]
+ public async Task