Skip to content
Bitzsoft.Integrationsbitzsoft.integrations

Concept

Express 快递

Express 域双接口变体——通用物流 IExpressProvider 与顺丰函证通 ISfLegalDocumentProvider 的职责边界、承运商识别、轨迹订阅与法律函件生命周期。

Last updated

Express 域覆盖物流轨迹查询、寄件下单、电子面单、运费预估等通用场景,外加顺丰函证通的法律函件寄递能力。和别的域不同,这里有两个接口,分别服务两套业务语义。本页解释双接口的职责边界与关键流程;精确的方法签名和 DTO 见 Express 抽象参考

域结构

Bitzsoft.Integrations.Express ← 抽象层(双接口 + 异常 + 模型 + 枚举)
├── Bitzsoft.Integrations.Express.Cainiao ← 菜鸟
├── Bitzsoft.Integrations.Express.ChinaPost ← 中国邮政
├── Bitzsoft.Integrations.Express.Kdniao ← 快递鸟
├── Bitzsoft.Integrations.Express.Kuaidi100 ← 快递100
├── Bitzsoft.Integrations.Express.SfLegal ← 顺丰函证通(法律函件)
├── Bitzsoft.Integrations.Express.ShowApi ← 聚合数据 ShowApi
├── Bitzsoft.Integrations.Express.Zto ← 中通
└── Bitzsoft.Integrations.Express.All ← 聚合包

为什么是两个接口

快递域里有两类业务,操作对象和语义完全不同:

  • 通用物流——运单轨迹查询、寄件下单、电子面单、运费时效。菜鸟、快递鸟、快递100 这些聚合平台或单一快递公司都做这件事,操作对象是”运单”。
  • 法律函件寄递——顺丰函证通面向律所、会计师事务所,提供法律函件的创建、寄递、签收、归档全生命周期管理。操作对象是”法律函件”,有签收确认和全流程记录这类法律语义。

如果把两者塞进一个 IExpressProvider,调用方会面对一堆对它毫无意义的方法——查物流的用不到”确认签收函件”,寄函件的用不到”识别快递公司”。强行统一只会稀释接口的语义清晰度。

所以这里拆成两个接口:通用物流走 IExpressProvider,法律函件走 ISfLegalDocumentProvider。顺丰函证通只实现后者,其余 6 家只实现前者,互不污染。两者的供应商集合完全不重叠——顺丰函证通的 Descriptor limitations 明确记录:“仅提供法律函件寄递生命周期,不注册通用 IExpressProvider。“

IExpressProvider:通用物流

8 个方法覆盖四类操作:

public interface IExpressProvider
{
string ProviderName { get; }
// ① 轨迹查询(实时 / 批量 / 订阅推送)
Task<ExpressTrackingInfo> TrackAsync(string trackingNumber, string? carrierCode = null, string? phoneSuffix = null, CancellationToken ct = default);
Task<IReadOnlyList<ExpressTrackingInfo>> BatchTrackAsync(IEnumerable<string> trackingNumbers, string? carrierCode = null, CancellationToken ct = default);
Task<ExpressSubscriptionResult> SubscribeAsync(string trackingNumber, string callbackUrl, string? carrierCode = null, CancellationToken ct = default);
// ② 寄件下单
Task<ExpressShipmentResult> CreateShipmentAsync(ExpressShipmentOrder order, CancellationToken ct = default);
Task CancelShipmentAsync(string orderId, CancellationToken ct = default);
// ③ 运费与面单
Task<IReadOnlyList<ExpressQuoteResult>> GetQuoteAsync(ExpressQuoteRequest request, CancellationToken ct = default);
Task<ExpressWaybillResult> GenerateWaybillAsync(ExpressShipmentOrder order, CancellationToken ct = default);
// ④ 快递公司识别
Task<ExpressCarrierInfo> DetectCarrierAsync(string trackingNumber, CancellationToken ct = default);
}

承运商识别

各家快递公司用不同的编码体系(快递鸟的 YTO、快递100 的 yuantong)。Express 域用统一的 ExpressCarrierCode 枚举(SF / YTO / ZTO / STO / YD / HTKY / JTSD / EMS / ChinaPost / JD / DBL / HHTT / ZJS / Cainiao)作为映射目标,各 Provider 内部维护平台编码到此枚举的映射。

DetectCarrierAsync 根据运单号自动识别快递公司,返回 ExpressCarrierInfo

字段说明
CarrierCode供应商侧编码
CarrierName快递公司名称
UnifiedCode统一枚举 ExpressCarrierCode
Confidence匹配置信度(0-1)

TrackAsynccarrierCode 参数可选——部分供应商支持仅凭单号自动识别承运商。

轨迹订阅模型

实时查询(TrackAsync / BatchTrackAsync)每次调用都向供应商拉取一次。当需要持续跟踪时,用 SubscribeAsync 注册订阅:供应商在运单状态变化时回调 callbackUrl,应用被动接收推送,无需轮询。

ExpressSubscriptionResultSuccessSubscriptionId(供应商返回)、失败时的 FailureReason。订阅成功后,应用需在 callbackUrl 实现 HTTP 接收端点解析供应商推送的轨迹数据。

电子面单

GenerateWaybillAsync 接收 ExpressShipmentOrder(与寄件下单同结构),返回 ExpressWaybillResult,含面单的 HTML 内容(HtmlContent)或 Base64 编码的 PDF(PdfBase64),以及打印尺寸描述(PrintSize)。

ISfLegalDocumentProvider:法律函件

顺丰函证通的法律函件寄递有独特语义——它不只是”寄个快递”,而是管理一份法律函件从创建到归档的完整记录:

public interface ISfLegalDocumentProvider
{
string ProviderName { get; }
// ① 创建法律函件寄递任务
Task<LegalDocumentShipmentResult> CreateDocumentShipmentAsync(LegalDocumentShipmentRequest request, CancellationToken ct = default);
// ② 查询寄递状态
Task<LegalDocumentTrackingResult> TrackDocumentAsync(string documentId, CancellationToken ct = default);
// ③ 确认签收(法律函件特有的回执环节)
Task ConfirmReceiptAsync(string documentId, CancellationToken ct = default);
// ④ 全流程记录(含创建、寄递、签收、归档)
Task<LegalDocumentFullRecord> GetFullRecordAsync(string documentId, CancellationToken ct = default);
}

法律函件生命周期

CreateDocumentShipmentAsync待寄出已寄出在途中已签收已拒收已退回ConfirmReceiptAsync 确认异常

Created

Pending

Sent

InTransit

Signed

Rejected

Returned

Exception

LegalDocumentShipmentRequest 相比通用寄件多了法律语义字段:

字段说明
DocumentType函件类型(律师函、催收函、仲裁通知书等,必填)
Title函件标题
CaseNumber关联案件编号
Sender / Receiver寄件人/收件人(ExpressContact

LegalDocumentFullRecord 是完整档案,含创建时间(CreatedTime)、寄出时间(SentTime)、签收时间(SignedTime)、签收人(SignedBy)、物流轨迹(Traces)——这是法律函件区别于普通快递的核心价值:可追溯的全流程证据链。

ConfirmReceiptAsync 是法律函件特有的”确认签收”环节,对应 LegalDocumentStatus.Signed 状态。状态枚举覆盖 Created / Pending / Sent / InTransit / Signed / Rejected / Returned / Exception 八种。

错误处理:ExpressException

失败时抛 ExpressException,沿用其他域的异常封装风格:

public sealed class ExpressException : IntegrationException
{
public string ProviderName => Provider ?? string.Empty;
public new string? ErrorCode => base.ErrorCode;
public new string? ProviderMessage => base.ProviderMessage;
public ExpressException(
string providerName, string message,
string? errorCode = null, string? providerMessage = null,
Exception? innerException = null)
: base(domain: "Express", message: $"[{providerName}] {message}", ...);
}

消息格式 [ProviderName] message。Express 域用异常风格,不用 Result 包装。这与 TeamWork 一致,但与新域(EnterpriseInfo / ElectronicSignature 的 Result 模式)不同。

厂商清单

厂商Provider ID实现接口能力定位
快递鸟 KdniaokdniaoIExpressProvider轨迹 + 寄件 + 面单
快递100 Kuaidi100kuaidi100IExpressProvider轨迹 + 订阅推送
菜鸟 CainiaocainiaoIExpressProvider轨迹 + 电子面单
中国邮政 ChinaPostchinapostIExpressProvider邮政轨迹与寄件
中通 ZtoztoIExpressProvider中通轨迹与寄件
聚合数据 ShowApishowapiIExpressProvider聚合轨迹查询
顺丰函证通 SfLegalsflegalISfLegalDocumentProvider法律函件全生命周期

两个接口的供应商集合完全不重叠。

注册模式

单厂商

// ① 通用物流——快递鸟
builder.Services.AddBitzsoftKdniaoExpress(builder.Configuration.GetSection("Express:Kdniao"));
// ② 法律函件——顺丰函证通
builder.Services.AddBitzsoftSfLegal(builder.Configuration.GetSection("Express:SfLegal"));

两个接口互不依赖,可以只注册通用物流,也可以只注册函件服务。

多厂商聚合

builder.Services.AddBitzsoftExpressAll(builder.Configuration, "Express");

All 聚合包按配置节存在性按需注册:

{
"Express": {
"Kdniao": { "EBusinessID": "...", "AppKey": "..." },
"Kuaidi100": { "Customer": "...", "Key": "..." },
"SfLegal": { "PartnerId": "...", "Checkword": "..." }
}
}

消费

通用物流

public class TrackingService(IExpressProvider express)
{
// 实时查轨迹
public async Task<ExpressTrackingInfo> TrackAsync(string trackingNumber)
=> await express.TrackAsync(trackingNumber);
// 寄件下单
public async Task<ExpressShipmentResult> ShipAsync(ExpressShipmentOrder order)
=> await express.CreateShipmentAsync(order);
// 订阅轨迹推送(被动接收,无需轮询)
public async Task SubscribeAsync(string trackingNumber, string callbackUrl)
=> await express.SubscribeAsync(trackingNumber, callbackUrl);
}

法律函件

public class LegalDocumentService(ISfLegalDocumentProvider sfLegal)
{
public async Task<string> DispatchAsync(LegalDocumentShipmentRequest request)
{
var result = await sfLegal.CreateDocumentShipmentAsync(request);
return result.DocumentId; // 函件 ID,后续用于查状态和签收
}
public async Task ConfirmAsync(string documentId)
{
await sfLegal.ConfirmReceiptAsync(documentId); // 法律函件特有的签收确认
}
public async Task<LegalDocumentFullRecord> ArchiveAsync(string documentId)
{
// 全流程记录作为法律证据归档
return await sfLegal.GetFullRecordAsync(documentId);
}
}

多厂商场景分别用 IIntegrationProviderResolver<IExpressProvider>IIntegrationProviderResolver<ISfLegalDocumentProvider> 按 Provider ID 解析。

相关

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%