📦 注文サービス
注文サービスは、ステータス管理とアイテム追跡を含む注文エンティティ管理のための完全なREST APIを提供します。Nodeblocks関数コンポジションアプローチを使用して構築され、MongoDBとシームレスに統合されます。
🚀 クイックスタート
import express from 'express';
import { MongoClient } from 'mongodb';
import { middlewares, services } from '@nodeblocks/backend-sdk';
const { nodeBlocksErrorMiddleware } = middlewares;
const { orderService } = services;
const client = new MongoClient('mongodb://localhost:27017').db('dev');
express()
.use(
orderService(
{
orders: client.collection('orders'),
identity: client.collection('identity'),
},
{
authSecrets: {
authEncSecret: 'your-encryption-secret',
authSignSecret: 'your-signing-secret',
},
user: {
typeIds: {
admin: '100',
guest: '000',
user: '001',
},
},
}
)
)
.use(nodeBlocksErrorMiddleware())
.listen(8089, () => console.log('注文サービスが起動しました'));
📋 エンドポイント概要
メソッド | パス | 説明 | 認証 |
---|---|---|---|
POST | /orders | 新規注文を作成 | Bearerトークン必須 |
GET | /orders/:orderId | IDで注文を取得 | Bearerトークン必須(本人/管理者) |
GET | /orders | 注文リストを取得 | Bearerトークン必須 |
PATCH | /orders/:orderId | 注文を更新 | Bearerトークン必須(本人/管理者) |
PATCH | /orders/:orderId/status | 注文ステータスを更新 | Bearerトークン必須(管理者) |
POST | /orders/:orderId/cancel | 注文をキャンセル | Bearerトークン必須(本人/管理者) |
GET | /orders/:orderId/tracking | 配送追跡情報を取得 | Bearerトークン必須(本人/管理者) |
🛒 注文操作
1. 注文作成
curl -X POST http://localhost:8089/orders \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"customerId": "user-uuid-here",
"items": [
{
"productId": "product-1-uuid",
"quantity": 2,
"unitPrice": 1299.99,
"name": "ノートパソコン"
},
{
"productId": "product-2-uuid",
"quantity": 1,
"unitPrice": 299.99,
"name": "マウス"
}
],
"shippingAddress": {
"name": "田中太郎",
"street": "東京都渋谷区神南1-1-1",
"city": "渋谷区",
"state": "東京都",
"postalCode": "150-0041",
"country": "Japan",
"phone": "+81-90-1234-5678"
},
"paymentMethod": {
"type": "credit_card",
"cardLast4": "1234"
}
}'
レスポンス:
{
"orderId": "order-uuid-here",
"orderNumber": "ORD-2024-001234",
"message": "注文が正常に作成されました",
"total": 2899.97,
"status": "pending"
}
2. 注文詳細取得
curl -X GET http://localhost:8089/orders/order-uuid-here \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
レスポンス例:
{
"id": "order-uuid-here",
"orderNumber": "ORD-2024-001234",
"customerId": "user-uuid-here",
"status": "confirmed",
"items": [
{
"productId": "product-1-uuid",
"name": "ノートパソコン",
"quantity": 2,
"unitPrice": 1299.99,
"totalPrice": 2599.98
}
],
"summary": {
"subtotal": 2599.98,
"tax": 259.99,
"shipping": 39.99,
"discount": 0,
"total": 2899.96
},
"shippingAddress": {
"name": "田中太郎",
"street": "東京都渋谷区神南1-1-1",
"city": "渋谷区",
"state": "東京都",
"postalCode": "150-0041",
"country": "Japan"
},
"tracking": {
"carrier": "ヤマト運輸",
"trackingNumber": "1234567890",
"status": "shipped",
"estimatedDelivery": "2024-01-20T15:00:00.000Z"
},
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-16T14:22:00.000Z"
}
📊 注文ステータス管理
ステータスフロー
pending → confirmed → processing → shipped → delivered
↓
cancelled
ステータス更新
# 注文確認
curl -X PATCH http://localhost:8089/orders/order-uuid-here/status \
-H "Authorization: Bearer ADMIN_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "confirmed",
"note": "在庫確認済み"
}'
# 発送処理
curl -X PATCH http://localhost:8089/orders/order-uuid-here/status \
-H "Authorization: Bearer ADMIN_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "shipped",
"tracking": {
"carrier": "ヤマト運輸",
"trackingNumber": "1234567890",
"shippedAt": "2024-01-16T09:00:00.000Z"
}
}'
注文キャンセル
curl -X POST http://localhost:8089/orders/order-uuid-here/cancel \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reason": "お客様都合",
"note": "商品が不要になりました"
}'
📊 データスキーマ
注文エンティティ
interface Order {
id: string; // 一意識別子
orderNumber: string; // 注文番号(一意)
customerId: string; // 顧客ID
status: OrderStatus; // 注文ステータス
items: OrderItem[]; // 注文商品
summary: OrderSummary; // 注文集計
shippingAddress: Address; // 配送先住所
billingAddress?: Address; // 請求先住所
paymentMethod: PaymentMethod; // 支払い方法
tracking?: TrackingInfo; // 配送追跡情報
notes?: string; // 備考
metadata?: Record<string, any>; // 追加メタデータ
createdAt: string; // 作成日時
updatedAt: string; // 更新日時
}
type OrderStatus =
| 'pending' // 保留中
| 'confirmed' // 確認済み
| 'processing' // 処理中
| 'shipped' // 発送済み
| 'delivered' // 配達完了
| 'cancelled'; // キャンセル
interface OrderItem {
productId: string;
name: string;
quantity: number;
unitPrice: number;
totalPrice: number;
sku?: string;
specifications?: Record<string, any>;
}
interface OrderSummary {
subtotal: number; // 小計
tax: number; // 税額
shipping: number; // 送料
discount: number; // 割引額
total: number; // 合計
}
🔍 検索とフィルタリング
注文検索
# ステータスでフィルタ
curl -X GET "http://localhost:8089/orders?status=shipped" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
# 日付範囲でフィルタ
curl -X GET "http://localhost:8089/orders?from=2024-01-01&to=2024-01-31" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
# 注文番号で検索
curl -X GET "http://localhost:8089/orders?orderNumber=ORD-2024-001234" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
# 金額範囲でフィルタ
curl -X GET "http://localhost:8089/orders?minTotal=1000&maxTotal=5000" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
# ページネーション
curl -X GET "http://localhost:8089/orders?page=1&limit=20&sort=created_at&order=desc" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
🚚 配送追跡
追跡情報取得
curl -X GET http://localhost:8089/orders/order-uuid-here/tracking \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
レスポンス:
{
"orderId": "order-uuid-here",
"carrier": "ヤマト運輸",
"trackingNumber": "1234567890",
"status": "in_transit",
"estimatedDelivery": "2024-01-20T15:00:00.000Z",
"events": [
{
"status": "shipped",
"location": "東京配送センター",
"timestamp": "2024-01-16T09:00:00.000Z",
"description": "商品が発送されました"
},
{
"status": "in_transit",
"location": "配送中",
"timestamp": "2024-01-17T14:30:00.000Z",
"description": "配送中です"
}
]
}
🧪 テスト例
describe('注文サービス', () => {
test('注文作成が成功する', async () => {
const orderData = {
customerId: 'customer-uuid',
items: [
{
productId: 'product-uuid',
quantity: 1,
unitPrice: 1000,
name: 'テスト商品'
}
],
shippingAddress: testAddress
};
const response = await request(orderApp)
.post('/orders')
.set('Authorization', `Bearer ${customerToken}`)
.send(orderData)
.expect(201);
expect(response.body.message).toBe('注文が正常に作成されました');
expect(response.body.total).toBe(1000);
});
test('注文ステータス更新が成功する', async () => {
const order = await createTestOrder();
const response = await request(orderApp)
.patch(`/orders/${order.id}/status`)
.set('Authorization', `Bearer ${adminToken}`)
.send({ status: 'confirmed' })
.expect(200);
expect(response.body.status).toBe('confirmed');
});
});