| name | logistics-adapters |
| description | Taiwan logistics integration (台灣物流整合). Use when working with CTC (中華宅配/宅配通), T-CAT (黑貓宅急便), or Taiwan delivery services. Covers package tracking (貨件追蹤), shipment creation (建立託運單), delivery status (配送狀態), and batch operations (批次追蹤). Keywords: 物流, 宅配, 貨運, 出貨, 寄送, logistics, shipping, delivery, tracking, CTC, TCAT, 黑貓, 中華宅配
|
Taiwan Logistics Adapters (台灣物流適配器)
Overview
@rytass/logistics 系列套件提供統一的台灣物流服務整合介面,支援包裹追蹤、訂單建立和狀態管理。
套件清單
| 套件 | 說明 | 功能 |
|---|
@rytass/logistics | 基礎介面 | 定義統一的物流服務介面 |
@rytass/logistics-adapter-tcat | 黑貓宅急便 | 包裹追蹤(HTML 爬蟲) |
@rytass/logistics-adapter-ctc | 中華宅配 | 包裹追蹤 + 訂單管理(REST API) |
Quick Start
安裝
npm install @rytass/logistics-adapter-tcat
npm install @rytass/logistics-adapter-ctc
黑貓宅急便追蹤
import { TCatLogisticsService, TCatLogistics } from '@rytass/logistics-adapter-tcat';
const logistics = new TCatLogisticsService(TCatLogistics);
const [result] = await logistics.trace('800978442950');
console.log(result.statusHistory);
const results = await logistics.trace(['800978442950', '903404283301']);
中華宅配追蹤與建單
⚠️ 安全警告:預設的 CtcLogistics 配置包含測試用的 API Token,請勿用於生產環境。務必使用您自己的 API Token。
import { CtcLogisticsService, CtcLogistics } from '@rytass/logistics-adapter-ctc';
const logistics = new CtcLogisticsService({
...CtcLogistics,
apiToken: process.env.CTC_API_TOKEN!,
});
const [result] = await logistics.trace('TRACKING-001');
const order = await logistics.create({
senderCompany: '寄件公司',
senderAddress: '台北市中正區重慶南路一段122號',
senderMobile: '0912345678',
receiverCompany: '收件公司',
receiverContactName: '收件人',
receiverAddress: '台北市信義區信義路五段7號',
receiverMobile: '0987654321',
paidCode: '客戶宅配',
});
console.log(order.shippingNumber);
console.log(order.trackingNumber);
const updatedOrder = await logistics.update({
trackingNumber: 'TRACKING-001',
senderCompany: '新寄件公司',
senderAddress: '台北市中正區重慶南路一段122號',
senderMobile: '0912345678',
receiverCompany: '新收件公司',
receiverContactName: '新收件人',
receiverAddress: '台北市信義區信義路五段7號',
receiverMobile: '0987654321',
paidCode: '客戶宅配',
});
CTC 建單/更新選項
interface CreateOrUpdateCtcLogisticsOptions {
trackingNumber?: string;
customerDepartmentId?: number;
customerDepartmentUnitId?: number;
senderCompany: string;
senderContactName?: string;
senderAddress: string;
senderTel?: string;
senderMobile?: string;
senderRemark?: string;
receiverCompany: string;
receiverContactName: string;
receiverAddress: string;
receiverTel?: string;
receiverMobile?: string;
receiverRemark?: string;
paidCode: string;
shipmentContent?: string;
transportation?: string;
shippingMethod?: string;
payer?: string;
shippingTime?: string;
paymentMethod?: string;
quantity?: number;
weight?: number;
volume?: number;
}
interface CtcLogisticsDto {
trackingNumber?: string;
shippingNumber: string;
}
Core Concepts
統一介面 LogisticsService
所有適配器都實現 LogisticsService 介面:
interface LogisticsInterface<T = LogisticsBaseStatus> {
reference?: T;
url: string;
}
interface LogisticsService<LogisticsType extends LogisticsInterface<LogisticsStatus<LogisticsType>>> {
trace(request: string): Promise<LogisticsTraceResponse<LogisticsType>[]>;
trace(request: string[]): Promise<LogisticsTraceResponse<LogisticsType>[]>;
}
追蹤結果結構
interface LogisticsTraceResponse<K extends LogisticsInterface<LogisticsStatus<K>>> {
logisticsId: string;
statusHistory: LogisticsStatusHistory<K['reference']>[];
}
interface LogisticsStatusHistory<T> {
date: string;
status: T;
}
interface TCatLogisticsStatusHistory<T> extends LogisticsStatusHistory<T> {
businessPremise: string;
}
interface CtcLogisticsStatusHistory<T> extends LogisticsStatusHistory<T> {
statusCode: CtcLogisticsStatusEnum;
}
enum CtcLogisticsStatusEnum {
CREATED = 10,
PICKUP_EXCEPTION = 29,
PICKED_UP = 30,
PICKUP_ARRIVED_AT_HUB = 40,
IN_TRANSIT = 50,
TRANSIT_ARRIVED_AT_HUB = 60,
SHELVED = 65,
DELIVERING = 70,
DELIVERY_EXCEPTION = 75,
DELIVERED = 80,
EMPTY_TRIP = 87,
COMPLETED = 88,
NOTIFICATION_SENT = 91,
CANCELLED = 99,
}
基本狀態類型
type LogisticsBaseStatus = 'DELIVERED' | 'DELIVERING' | 'SHELVED';
type TCatLogisticsStatus =
| 'DELIVERED'
| 'TRANSPORTING'
| 'DELIVERING'
| 'COLLECTING'
| 'CONSOLIDATED'
| 'PICKUP_CANCELED'
| 'SHELVED'
| 'INVESTIGATING'
| 'DELIVERING_TODAY'
| 'FAIL_PICKUP'
| 'AWAY_HOME'
| LogisticsBaseStatus;
type CtcLogisticsStatus =
| 'CREATED'
| 'PICKUP_EXCEPTION'
| 'PICKED_UP'
| 'PICKUP_ARRIVED_AT_HUB'
| 'IN_TRANSIT'
| 'TRANSIT_ARRIVED_AT_HUB'
| 'SHELVED'
| 'DELIVERING'
| 'DELIVERY_EXCEPTION'
| 'DELIVERED'
| 'EMPTY_TRIP'
| 'COMPLETED'
| 'NOTIFICATION_SENT'
| 'CANCELLED';
額外導出類型
interface LogisticsErrorInterface {
readonly code: string;
readonly message?: string;
}
interface TCatLogisticsInterface<T> extends LogisticsInterface<T> {
ignoreNotFound: boolean;
statusMap: (html: string, id: string) => LogisticsStatusHistory<T>[];
}
interface CtcLogisticsInterface<T> extends LogisticsInterface<T> {
apiToken: string;
ignoreNotFound?: boolean;
}
const CtcLogisticsStatusMap: { [key: string]: CtcLogisticsStatus };
interface CreateOrUpdateCtcLogisticsResponse {
success: boolean;
error: string;
shipping_number: string;
tracking_number?: string;
}
Common Patterns
T-CAT 狀態對照表
| 狀態 | 中文原文 | 說明 |
|---|
DELIVERED | 順利送達 | 包裹已成功送達 |
TRANSPORTING | 轉運中 | 包裹在轉運途中 |
DELIVERING | 配送中 | 配送員正在派送 |
COLLECTING | 取件中 | 正在取件 |
CONSOLIDATED | 已集貨 | 已完成集貨 |
PICKUP_CANCELED | 取消取件 | 取件已取消 |
SHELVED | 暫置營業所 | 暫存於營業所 |
INVESTIGATING | 調查處理中 | 正在調查處理 |
DELIVERING_TODAY | 配送中(當配下車) (當配上車) | 當日配送中 |
FAIL_PICKUP | 未順利取件,請洽客服中心 | 取件失敗 |
AWAY_HOME | 不在家.公司行號休息 | 收件人不在 |
CTC 狀態對照表
| 狀態 | 狀態碼 | 說明 |
|---|
CREATED | 10 | 新單 |
PICKUP_EXCEPTION | 29 | 取件異常 |
PICKED_UP | 30 | 已取件 |
PICKUP_ARRIVED_AT_HUB | 40 | 取件到站 |
IN_TRANSIT | 50 | 轉運中 |
TRANSIT_ARRIVED_AT_HUB | 60 | 轉運到站 |
SHELVED | 65 | 回站保管 |
DELIVERING | 70 | 配送中 |
DELIVERY_EXCEPTION | 75 | 配送異常 |
DELIVERED | 80 | 配送完成 |
EMPTY_TRIP | 87 | 空趟 |
COMPLETED | 88 | 正常結案 |
NOTIFICATION_SENT | 91 | 通知完成 |
CANCELLED | 99 | 取消 |
錯誤處理
import { LogisticsError, ErrorCode } from '@rytass/logistics';
enum ErrorCode {
NOT_IMPLEMENTED = '999',
NOT_FOUND_ERROR = '101',
PERMISSION_DENIED = '102',
INVALID_PARAMETER = '103',
}
try {
const result = await logistics.trace('INVALID');
} catch (error) {
if (error instanceof LogisticsError) {
switch (error.code) {
case ErrorCode.NOT_FOUND_ERROR:
console.error('找不到此包裹');
break;
case ErrorCode.PERMISSION_DENIED:
console.error('無權查詢');
break;
case ErrorCode.INVALID_PARAMETER:
console.error('無效的追蹤號碼');
break;
case ErrorCode.NOT_IMPLEMENTED:
console.error('功能未實作');
break;
}
}
}
忽略找不到錯誤
const tcatLogistics = new TCatLogisticsService({
...TCatLogistics,
ignoreNotFound: true,
});
const ctcLogistics = new CtcLogisticsService({
...CtcLogistics,
apiToken: 'your-token',
ignoreNotFound: false,
});
API Reference
詳細 API 文件請參閱 reference.md。
Troubleshooting
T-CAT 追蹤失敗
T-CAT 使用 HTML 爬蟲,可能因網站改版而失效。檢查:
- 網站是否可正常訪問
- HTML 結構是否變更
- 考慮使用自訂
statusMap 函數
CTC API 認證失敗
- 確認
apiToken 正確
- 檢查 API 端點 URL
- 確認帳戶有對應權限
批量追蹤效能
批量追蹤使用 Promise.all,注意:
- 避免一次追蹤過多包裹
- 考慮分批處理大量請求
- 設置適當的超時時間