配送計算プラグイン (Shipping Calculator Plugin)¶
概要¶
Ritsubiのブランド別配送料金と直送モード(+10%サーチャージ)を計算するVendureカスタムプラグイン。複雑な配送料金体系とゾーン別料金設定に対応します。
互換性レンジ¶
- Vendure: 3.5.x(apps/vendure-server は ^3.5.1 を使用)
- Node.js: >=22.11.0(apps/vendure-server/package.json の engines に準拠)
パッケージ情報¶
- パッケージ名:
@ritsubi/shipping-calculator-plugin - パス:
/packages/plugins/shipping-calculator - エントリーポイント:
src/index.ts
実装機能¶
1. ブランド別配送料金計算¶
商品ブランド(エクスビアンス、メソセウティカル、美容機器消耗品)ごとに異なる配送料金を適用。
ブランド別配送料金例¶
| ブランド | 基本配送料 | 無料配送閾値 |
|---|---|---|
| エクスビアンス | 800円 | 10,000円以上 |
| メソセウティカル | 1,200円 | 15,000円以上 |
| 美容機器消耗品 | 1,500円 | 20,000円以上 |
2. 直送モード追加料金(10%サーチャージ)¶
顧客が「ユーザー直送モード」を選択した場合、注文小計の10%を配送料に追加。
直送モード計算式¶
基本配送料 = ブランド別配送料金
直送サーチャージ = 注文小計 × 0.10
最終配送料 = 基本配送料 + 直送サーチャージ
例: 注文小計50,000円の場合¶
基本配送料: 800円
直送サーチャージ: 50,000円 × 0.10 = 5,000円
最終配送料: 800円 + 5,000円 = 5,800円
3. 配送ゾーン別料金設定¶
日本国内の配送エリアをゾーン分けし、エリアごとに異なる配送料金を設定。
配送ゾーン例¶
| ゾーン | 対象地域 | 追加料金 |
|---|---|---|
| 通常エリア | 本州・四国・九州 | +0円 |
| 遠隔地 | 北海道 | +500円 |
| 離島 | 沖縄・離島 | +1,000円 |
4. 無料配送閾値管理¶
購入金額が一定額を超えた場合、配送料を無料にする制御。
- ブランドごとに異なる閾値を設定可能
- キャンペーン期間中の一時的な閾値変更に対応
5. 特別取り扱い料金¶
冷蔵・冷凍配送、大型商品など、特別な取り扱いが必要な商品に追加料金を適用。
技術仕様¶
プラグイン設定オプション¶
// プラグインは現在オプションなしで動作
export class RitsubiShippingCalculatorPlugin {
static init(options?: {}) {
this.options = options ?? {};
return RitsubiShippingCalculatorPlugin;
}
}
プラグイン初期化¶
import { RitsubiShippingCalculatorPlugin } from '@ritsubi/shipping-calculator-plugin';
export const config: VendureConfig = {
plugins: [RitsubiShippingCalculatorPlugin.init()],
shippingOptions: {
shippingCalculators: [
// RitsubiShippingCalculatorは自動登録される
],
},
};
エンティティ¶
ShippingModeEntity¶
配送モード(通常配送 or 直送モード)を管理するエンティティ。
@Entity()
export class ShippingModeEntity extends VendureEntity {
@Column()
orderId: string;
@Column('enum', { enum: ['STANDARD', 'DIRECT_SHIPPING'] })
mode: ShippingMode;
@Column('decimal', { precision: 10, scale: 2 })
surchargeAmount: number; // 直送サーチャージ金額
@Column('decimal', { precision: 5, scale: 2 })
surchargeRate: number; // サーチャージ率(通常0.10 = 10%)
@Column()
appliedAt: Date;
}
BrandShippingRuleEntity¶
ブランドごとの配送ルールを定義するエンティティ。
@Entity()
export class BrandShippingRuleEntity extends VendureEntity {
@Column()
brandCode: string;
@Column()
brandName: string;
@Column('decimal', { precision: 10, scale: 2 })
baseShippingFee: number; // 基本配送料
@Column('decimal', { precision: 10, scale: 2 })
freeShippingThreshold: number; // 無料配送閾値
@Column('jsonb')
zoneSpecificFees: Record<string, number>; // ゾーン別追加料金
@Column()
effectiveFrom: Date;
@Column({ nullable: true })
effectiveTo: Date;
}
サービス¶
RitsubiShippingCalculatorService¶
配送料金計算のコアロジックを担当するサービス。
主要メソッド:
calculate(ctx: RequestContext, order: Order): Promise<PriceCalculationResult>- 注文全体の配送料を計算
calculateBrandShipping(brandCode: string, orderTotal: number, zone: string): Promise<number>- ブランド別配送料を計算
calculateDirectShippingSurcharge(orderSubtotal: number, rate: number): Promise<number>- 直送サーチャージを計算
isFreeShippingEligible(brandCode: string, orderTotal: number): Promise<boolean>- 無料配送対象かどうかを判定
ShippingModeService¶
配送モードの管理を行うサービス。
主要メソッド:
setShippingMode(orderId: ID, mode: ShippingMode): Promise<void>- 注文の配送モードを設定
getShippingMode(orderId: ID): Promise<ShippingMode>- 注文の配送モードを取得
calculateSurcharge(orderId: ID): Promise<number>- 直送サーチャージ金額を計算
Vendure ShippingCalculator 統合¶
RitsubiShippingCalculator¶
Vendureの ShippingCalculator インターフェースを実装。
const RitsubiShippingCalculator = new ShippingCalculator({
code: 'ritsubi-shipping-calculator',
description: [
{
languageCode: LanguageCode.ja,
value: 'ブランド別配送料金と直送サーチャージを計算',
},
],
args: {},
calculate: (ctx, order, _args, _method) => {
return calculatorService.calculate(ctx, order);
},
});
対応する要件¶
要件定義書との対応¶
- 直送モード追加料金: 注文小計の10%サーチャージ計算
- ブランド別配送料金: エクスビアンス、メソセウティカル、美容機器消耗品の配送料金体系
- 配送ゾーン管理: 日本国内のエリア別料金設定
使用例¶
フロントエンド(Next.js)での使用¶
// 配送料をプレビュー
const { data } = await apolloClient.query({
query: PREVIEW_SHIPPING_COST,
variables: {
orderId: currentOrder.id,
shippingMode: 'DIRECT_SHIPPING', // or 'STANDARD'
zone: 'HOKKAIDO',
},
});
console.log(`基本配送料: ${data.baseShippingFee}円`);
console.log(`直送サーチャージ: ${data.surcharge}円`);
console.log(`最終配送料: ${data.totalShippingCost}円`);
配送モードの切り替え¶
// 直送モードに切り替え
await apolloClient.mutate({
mutation: SET_SHIPPING_MODE,
variables: {
orderId: currentOrder.id,
mode: 'DIRECT_SHIPPING',
},
});
// 配送料を再計算
await apolloClient.mutate({
mutation: RECALCULATE_SHIPPING,
variables: { orderId: currentOrder.id },
});
管理画面での使用¶
// ブランド別配送ルール設定
await brandShippingRuleService.createRule({
brandCode: 'EXUVIANCE',
brandName: 'エクスビアンス',
baseShippingFee: 800,
freeShippingThreshold: 10000,
zoneSpecificFees: {
HOKKAIDO: 500,
OKINAWA: 1000,
},
});
// 配送料金のバッチ再計算
await shippingCalculatorService.recalculateAllPendingOrders();
計算フロー¶
配送料計算の詳細フロー¶
1. 注文内容を取得
├─ 商品のブランドを識別
├─ 注文小計を取得
└─ 配送先ゾーンを取得
2. ブランド別基本配送料を計算
├─ ブランドコードからルールを取得
├─ 配送ゾーン追加料金を適用
└─ 無料配送閾値をチェック
3. 直送モードの場合
├─ 注文小計 × 10% を計算
└─ サーチャージを追加
4. 特別取り扱い料金を加算
└─ 冷蔵・大型商品の追加料金
5. 最終配送料を返す
データモデル¶
カスタムフィールド¶
Order.shippingMode- 配送モード(STANDARD or DIRECT_SHIPPING)Order.directShippingSurcharge- 直送サーチャージ金額Order.shippingZone- 配送ゾーンProduct.brandCode- 商品ブランドコードProduct.requiresSpecialHandling- 特別取り扱い要否
セキュリティ考慮事項¶
- 配送料金の検証: フロントエンドからの配送料は信頼せず、バックエンドで再計算
- モード変更権限: 配送モード変更は顧客本人または管理者のみ
- 料金履歴の保存: すべての配送料計算結果を記録
パフォーマンス最適化¶
- 配送ルールキャッシング: ブランド別配送ルールをRedisにキャッシュ
- バッチ計算: 大量の配送料再計算はバックグラウンドで処理
- ゾーン情報の前処理: 郵便番号からゾーンへの変換を事前にキャッシュ
トラブルシューティング¶
よくある問題¶
問題: 配送料が異常に高い
- 原因: 直送サーチャージが二重に適用されている
- 解決: 配送モードの設定を確認
問題: 無料配送が適用されない
- 原因: ブランド別配送ルールの閾値設定ミス
- 解決:
BrandShippingRuleEntityのfreeShippingThresholdを確認
関連ドキュメント¶
- 価格システムプラグイン - 価格計算との連携
- SMILE連携プラグイン - 配送情報のCSV出力
今後の拡張予定¶
- 配送日時指定機能
- 配送業者別料金設定
- リアルタイム配送料見積もりAPI連携
- 梱包サイズ別配送料計算