配送管理
joe edited this page 2026-08-11 14:01:25 +09:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

配送管理モジュール設計

概要

商品仕入れ・通販発送などあらゆる配送の追跡番号管理と送り状印刷を統合した配送管理モジュール。

機能要件

1. 追跡番号管理

  • 独立した追跡番号テーブル
  • 任意のエンティティ(商品、注文など)に紐付け可能
  • 送信/受信の区別
  • 複数梱包対応(1商品に複数追跡番号)

2. 追跡状況表示

  • プログレスバーで追跡状況を可視化
  • ステータス:未発送 → 輸送中 → 配達中 → 配達済み
  • 最新更新日時表示
  • 追跡履歴表示

3. 自動追跡

  • 各社の追跡APIを定期的に呼び出し
  • ステータス変更時に通知
  • 手動更新ボタン

4. 送り状印刷

  • 各社専用送り状フォーマット対応
  • 追跡番号の自動入力
  • 配送情報の自動入力
  • プレビュー機能
  • PDF印刷または直接印刷

5. 送付先管理

  • よく使う送付先の登録
  • デフォルト送付先設定
  • 送付先の自動補完

データモデル

Trackingモデル(新規)

class Tracking {
  final String id;
  final String trackingNumber;      // 追跡番号
  final String carrier;              // 宅配便会社 (yamato, sagawa, jp_post, other)
  final TrackingDirection direction; // 送信/受信
  final TrackingStatus status;       // 追跡ステータス
  final DateTime? shippedAt;        // 発送日
  final DateTime? deliveredAt;      // 配達日
  final DateTime? trackingUpdatedAt; // 追跡更新日時
  final String? notes;              // メモ
  
  // 紐付け先(任意)
  final String? entityType;        // エンティティ種別 (product, order, purchase, etc.)
  final String? entityId;          // エンティティID
  final String? entityName;        // 表示用エンティティ名
}

enum TrackingDirection {
  outbound('送信', '発送'),
  inbound('受信', '受取');
  
  final String displayName;
  final String label;
}

enum TrackingStatus {
  notShipped('未発送', 0),
  pickedUp('集荷済み', 10),
  inTransit('輸送中', 25),
  outForDelivery('配達中', 75),
  delivered('配達済み', 100),
  failed('配達失敗', 0),
  returned('返送', 0);
  
  final String displayName;
  final int progress;
}

追跡履歴モデル(新規)

class TrackingEvent {
  final String id;
  final String trackingId;
  final String status;
  final String location;
  final DateTime timestamp;
  final String? description;
}

ShippingLabelモデル(新規)

class ShippingLabel {
  final String id;
  final String carrier;              // 宅配便会社
  final String labelType;            // 送り状種別
  final String trackingNumber;      // 追跡番号
  final String senderName;          // 送付者名
  final String senderZip;           // 送付者郵便番号
  final String senderAddress;       // 送付者住所
  final String senderPhone;         // 送付者電話
  final String recipientName;       // 宛先名
  final String recipientZip;        // 宛先郵便番号
  final String recipientAddress;    // 宛先住所
  final String recipientPhone;      // 宛先電話
  final String? recipientCompany;  // 宛先会社名
  final String? contents;          // 内容品
  final int? quantity;             // 個数
  final int? weight;               // 重量(g)
  final String? serviceType;      // サービスタイプ
  final String? codAmount;        // 代引金額
  final DateTime createdAt;
  final DateTime? printedAt;
  
  // 紐付け先
  final String? entityType;
  final String? entityId;
}

送付先モデル(新規)

class ShippingAddress {
  final String id;
  final String name;
  final String company;
  final String zip;
  final String address;
  final String phone;
  final bool isDefault;
}

宅配便会社定義

enum Carrier {
  yamato('ヤマト', 'クロネコヤマト'),
  sagawa('佐川急便', '佐川急便'),
  jpPost('日本郵便', '日本郵便'),
  other('その他', null);
  
  final String displayName;
  final String? apiName;
}

送り状種別定義

enum LabelType {
  yamatoNeko('ヤマトネコポス', 'yamato'),
  yamatoCool('ヤマトクール便', 'yamato'),
  sagawa('佐川急便', 'sagawa'),
  jpPostYuupack('ゆうパック', 'jp_post'),
  jpPostLetter('レターパック', 'jp_post'),
  generic('汎用', 'generic');
  
  final String displayName;
  final String carrier;
}

追跡API

方針

  1. 各社API直接呼び出し(推奨)

    • ヤマトン:クロネコヤマトAPI
    • 佐川急便:e飛伝システムAPI
    • 日本郵便:追跡サービスAPI
  2. 共通APIサービス(代替案)

    • AfterShip
    • Track24
    • Ship24

API実装

ヤマトン

  • エンドポイント:https://toi.kuronekoyamato.co.jp/cgi-bin/tneko
  • メソッド:POST
  • パラメータ:number01(追跡番号)

佐川急便

  • エンドポイント:https://k2k.sagawa-exp.co.jp/p/web/okurijosearch.do
  • メソッド:POST
  • パラメータ:no1(追跡番号)

日本郵便

  • エンドポイント:https://tracking.post.japanpost.jp/services/srv/search/direct?searchLang=ja&locale=ja&reqCodeNo1={trackingNumber}
  • メソッド:GET

サービスクラス

class TrackingService {
  Future<TrackingStatus> getTrackingStatus(String carrier, String trackingNumber) async {
    switch (carrier) {
      case 'yamato':
        return _getYamatoTracking(trackingNumber);
      case 'sagawa':
        return _getSagawaTracking(trackingNumber);
      case 'jp_post':
        return _getJpPostTracking(trackingNumber);
      default:
        throw UnimplementedError('Unsupported carrier');
    }
  }
  
  Future<List<TrackingEvent>> getTrackingHistory(String carrier, String trackingNumber) async { ... }
  Future<TrackingStatus> _getYamatoTracking(String number) async { ... }
  Future<TrackingStatus> _getSagawaTracking(String number) async { ... }
  Future<TrackingStatus> _getJpPostTracking(String number) async { ... }
}

送り状フォーマット

ヤマトン送り状

┌─────────────────────────────────┐
│ クロネコヤマト                  │
│ 送り状                            │
├─────────────────────────────────┤
│ 追跡番号:1234-5678-9012         │
│                                 │
│ 送付者                           │
│ 山田 太郎                        │
│ 〒123-4567                       │
│ 東京都渋谷区...                  │
│ TEL:03-1234-5678                │
├─────────────────────────────────┤
│ 宛先                             │
│ 佐藤 花子                        │
│ ABC株式会社                      │
│ 〒987-6543                       │
│ 大阪府大阪市...                  │
│ TEL:06-9876-5432                │
├─────────────────────────────────┤
│ 内容品:商品                      │
│ 個数:1個                        │
│ 重量:500g                       │
│ サービス:ネコポス              │
└─────────────────────────────────┘

佐川急便送り状

┌─────────────────────────────────┐
│ 佐川急便                         │
│ 送り状                            │
├─────────────────────────────────┤
│ 追跡番号:9876-5432-1098         │
│                                 │
│ 送付者/宛先情報...               │
└─────────────────────────────────┘

日本郵便ゆうパック送り状

┌─────────────────────────────────┐
│ ゆうパック                        │
│ 送り状                            │
├─────────────────────────────────┤
│ 追跡番号:5555-6666-7777         │
│                                 │
│ 送付者/宛先情報...               │
└─────────────────────────────────┘

UI設計

1. 配送管理トップ画面(新規)

配送管理
├── タブ
│   ├── 追跡一覧
│   ├── 送り状印刷
│   └── 送付先管理
└── [追跡番号追加] ボタン

2. 追跡一覧画面

追跡一覧
├── フィルタ
│   ├── ステータス(全て/未発送/輸送中/配達済み)
│   ├── 宅配便会社
│   └── 送信/受信
└── 追跡リスト
    ├── 商品A [ヤマト] [送信] [輸送中] [===------]
    ├── 商品B [佐川] [送信] [配達中] [======---]
    └── 商品C [日本郵便] [受信] [配達済み] [=========]

3. 追跡詳細画面

追跡詳細:1234-5678-9012
├── 宅配便会社:ヤマト
├── 送信/受信:送信
├── ステータス:輸送中
├── プログレスバー:[===------] 25%
├── 最終更新:2024-06-22 14:30
├── 発送日:2024-06-20
├── 追跡履歴
│   ├── 2024-06-22 14:30 輸送中(東京配送センター)
│   ├── 2024-06-21 09:15 集荷済み(仙台営業所)
│   └── 2024-06-20 16:30 発送(仙台営業所)
└── [送り状印刷] ボタン

4. 送り状印刷画面

送り状印刷
├── 宅配便会社(ドロップダウン)
├── 送り状種別(ドロップダウン)
├── 追跡番号(テキスト入力 or 追跡番号選択)
├── 送付者情報
│   ├── 名前
│   ├── 郵便番号
│   ├── 住所
│   └── 電話番号
├── 宛先情報
│   ├── 名前
│   ├── 会社名
│   ├── 郵便番号
│   ├── 住所
│   └── 電話番号
├── 配送情報
│   ├── 内容品
│   ├── 個数
│   ├── 重量
│   └── サービスタイプ
├── [プレビュー] ボタン
└── [印刷] ボタン

5. 送付先管理画面

送付先管理
├── [送付先追加] ボタン
└── 送付先リスト
    ├── 佐藤 花子(ABC株式会社)[デフォルト]
    ├── 鈴木 一郎(XYZ商事)
    └── ...

6. 商品詳細画面拡張

商品詳細
├── 商品情報
├── 仕入れ情報
├── 追跡状況
│   ├── [追跡番号追加] ボタン
│   └── 追跡一覧
└── [送り状印刷] ボタン

印刷実装

PDF生成

class ShippingLabelPrinter {
  Future<void> printLabel(ShippingLabel label) async {
    final pdf = await _generatePdf(label);
    await Printing.layoutPdf(onLayout: (format) => pdf.save());
  }
  
  Future<void> savePdf(ShippingLabel label) async {
    final pdf = await _generatePdf(label);
    await Printing.sharePdf(bytes: await pdf.save(), filename: 'shipping_label.pdf');
  }
  
  Future<pw.Document> _generatePdf(ShippingLabel label) async {
    switch (label.carrier) {
      case 'yamato':
        return _generateYamatoLabel(label);
      case 'sagawa':
        return _generateSagawaLabel(label);
      case 'jp_post':
        return _generateJpPostLabel(label);
      default:
        return _generateGenericLabel(label);
    }
  }
}

各社フォーマット実装

Future<pw.Document> _generateYamatoLabel(ShippingLabel label) async {
  final pdf = pw.Document();
  pdf.addPage(pw.Page(
    pageFormat: PdfPageFormat.a4,
    build: (context) => pw.Column(
      children: [
        pw.Text('クロネコヤマト', style: pw.TextStyle(fontSize: 20, fontWeight: pw.FontWeight.bold)),
        pw.Text('送り状', style: pw.TextStyle(fontSize: 16)),
        pw.SizedBox(height: 20),
        pw.Text('追跡番号:${label.trackingNumber}'),
        pw.SizedBox(height: 20),
        pw.Text('送付者'),
        pw.Text(label.senderName),
        pw.Text('〒${label.senderZip}'),
        pw.Text(label.senderAddress),
        pw.Text('TEL:${label.senderPhone}'),
        pw.SizedBox(height: 20),
        pw.Text('宛先'),
        pw.Text(label.recipientName),
        if (label.recipientCompany != null) pw.Text(label.recipientCompany!),
        pw.Text('〒${label.recipientZip}'),
        pw.Text(label.recipientAddress),
        pw.Text('TEL:${label.recipientPhone}'),
        pw.SizedBox(height: 20),
        pw.Text('内容品:${label.contents ?? ''}'),
        pw.Text('個数:${label.quantity ?? 0}個'),
        pw.Text('重量:${label.weight ?? 0}g'),
      ],
    ),
  ));
  return pdf;
}

バックグラウンド処理

定期更新

  • WorkManagerまたはflutter_background_serviceを使用
  • 更新間隔:1時間ごと
  • 手動更新も可能

通知

  • ステータス変更時に通知
  • 配達済み時に通知
  • 配達失敗時に通知

連携機能

追跡と送り状の連携

  • 追跡番号登録時に送り状印刷を促す
  • 送り状印刷時に追跡番号を自動登録
  • 追跡状況と送り状情報の一元管理

商品モジュールとの連携

  • 商品詳細から追跡番号追加
  • 商品詳細から送り状印刷
  • 商品情報(名前、重量など)を自動入力
  • 複数商品のバルク印刷

注文モジュールとの連携

  • 注文から追跡番号追加
  • 注文から送り状印刷
  • 注文情報(宛先、商品)を自動入力
  • 注文と追跡番号の紐付け

エラーハンドリング

APIエラー

  • ネットワークエラー:リトライ(最大3回)
  • 無効な追跡番号:エラーメッセージ表示
  • API制限:次回更新を延期

印刷エラー

  • プリンター接続エラー:エラーメッセージ表示
  • PDF生成エラー:エラーメッセージ表示
  • 用紙サイズエラー:警告表示

入力エラー

  • 必須項目未入力:エラーメッセージ表示
  • 郵便番号フォーマットエラー:バリデーション
  • 電話番号フォーマットエラー:バリデーション

実装スケジュール

Phase 1: データモデル

  • Trackingモデル作成
  • TrackingEventモデル作成
  • ShippingLabelモデル作成
  • ShippingAddressモデル作成
  • DBマイグレーション
  • 列挙型定義

Phase 2: 追跡API

  • TrackingService実装
  • 各社API実装
  • 追跡履歴取得実装
  • テスト

Phase 3: 送り状印刷

  • ShippingLabelPrinter実装
  • 各社フォーマット実装
  • 汎用フォーマット実装
  • テスト

Phase 4: UI実装

  • 配送管理トップ画面
  • 追跡一覧画面
  • 追跡詳細画面
  • 送り状印刷画面
  • 送り状プレビュー画面
  • 送付先管理画面

Phase 5: 既存画面拡張

  • 商品詳細画面拡張
  • 仕入れ画面拡張
  • 注文画面拡張

Phase 6: バックグラウンド処理

  • 定期更新実装
  • 通知実装

Phase 7: 統合

  • 追跡と送り状の連携
  • 商品モジュールとの統合
  • 注文モジュールとの統合

技術的考慮事項

APIレート制限

  • 各社APIのレート制限を確認
  • 適切な更新間隔を設定
  • 複数追跡番号のバルク更新

セキュリティ

  • 追跡番号は機密情報ではないが、HTTPS必須
  • APIキーが必要な場合は安全に管理

印刷品質

  • 高解像度PDF生成
  • バーコード印刷対応
  • 複数ページ対応

ユーザビリティ

  • 追跡番号の入力補助(カメラスキャン)
  • 宅配便会社の自動検出(番号パターンから)
  • 送付先の履歴
  • テンプレュー機能

パフォーマンス

  • 追跡情報のキャッシュ
  • PDF生成の高速化
  • バルク印刷対応
  • 効率的なバルク更新

使用例

商品仕入れ

商品Aを仕入れ
→ 追跡番号登録(受信)
→ 自動追跡開始
→ 配達時に通知

通販発送

注文123の商品を発送
→ 送り状印刷画面起動
→ 送付先・商品情報入力
→ 送り状印刷
→ 追跡番号自動登録(送信)
→ 自動追跡開始

その他配送

サンプル品を発送
→ 追跡番号登録(送信)
→ 送り状印刷
→ 追跡状況を管理

参考資料

各社APIドキュメント

類似機能

PDF生成ライブラリ