ユニバーサル コマース プロトコル(UCP)の対応
- Dominant language
- PHP
- Stars
- 92
- Forks
- 97
- Avg merge
- 4d 2h
- Merged PRs (30d)
- 9
Description
refs https://github.com/EC-CUBE/ec-cube/issues/6574
### 概要(Overview)
Google Merchant の ユニバーサル コマース プロトコル(UCP) を使用した購入完了機能の実装
https://developers.google.com/merchant/ucp/guides/checkout/native?hl=ja
> 2系に元々ある API 機能の実装は古すぎるので無視してよいと思います
### 期待する内容(Expect) or 要望(Requirement)
ユニバーサル コマース プロトコル(UCP)を使用して購入完了できる
---
## 実装必須の3つのエンドポイント
### 1. 購入手続きセッション作成エンドポイント
- **エンドポイント**: `POST /checkout-sessions`
- **役割**: ユーザーが商品購入を決定した際に、購入検討中の商品を含むセッションを作成
- **リクエスト**: 商品情報(ID、タイトル)、数量、通貨
- **レスポンス**: セッションID、合計額、税金(推定)、決済ハンドラー情報、利用規約・プライバシーポリシーへのリンク
### 2. セッション更新エンドポイント
- **エンドポイント**: `PUT /checkout-sessions/{id}`
- **役割**: 配送先住所更新時の税金・配送オプション再計算など、セッション情報の変更対応
- **リクエスト**: 更新された配送先、決済情報を含む完全なチェックアウトオブジェクト
- **レスポンス**: 再計算された税金、送料、合計額、配送方法オプション
### 3. セッション完了エンドポイント
- **エンドポイント**: `POST /checkout-sessions/{id}/complete`
- **役割**: ユーザーが「注文する」をクリックした際のセッション完了と注文確定
- **リクエスト**: 決済情報とリスクシグナル
- **レスポンス**: 注文IDと注文へのパーマリンクURL
---
## 追加が必要なデータフィールド
### 1. 新規テーブル: `dtb_checkout_session`(必須)
UCPのセッション管理用に新規テーブルが必要
| カラム名 | 型 | Default | Nullable | Comment |
|----------|------|---------|----------|---------|
| `checkout_session_id` | integer | (auto) | false | チェックアウトセッションID (PRIMARY KEY) |
| `session_id` | text | | false | UCPセッションID(UUID形式、UNIQUE) |
| `status` | smallint | 1 | false | セッション状態: 1=incomplete / 2=completed |
| `currency` | text | 'JPY' | false | 通貨コード |
| `expires_at` | timestamp | | true | セッション有効期限 |
| `order_id` | integer | | true | 関連受注ID(完了後に設定) |
| `order_temp_id` | text | | true | 関連受注一時ID |
| `buyer_data` | text | | true | 購入者情報(JSON: first_name, last_name, email) |
| `fulfillment_data` | text | | true | 配送先・配送方法選択情報(JSON) |
| `payment_data` | text | | true | 決済情報(JSON) |
| `selected_shipping_option` | text | | true | 選択された配送オプションID |
| `create_date` | timestamp | CURRENT_TIMESTAMP | false | 作成日時 |
| `update_date` | timestamp | | false | 更新日時 |
| `del_flg` | smallint | 0 | false | 削除フラグ |
**インデックス:**
- `dtb_checkout_session_session_id_key` ON (session_id) - UNIQUE
- `dtb_checkout_session_order_id_key` ON (order_id)
### 2. 店舗設定への追加フィールド(`dtb_baseinfo`)
| カラム名 | 型 | Default | Nullable | Comment |
|----------|------|---------|----------|---------|
| `privacy_policy_url` | text | | true | プライバシーポリシーURL |
| `terms_of_service_url` | text | | true | 利用規約URL |
| `ucp_enabled` | smallint | 0 | false | UCP機能有効フラグ (0=無効, 1=有効) |
| `google_pay_merchant_id` | text | | true | Google Pay マーチャントID |
| `google_pay_merchant_name` | text | | true | Google Pay マーチャント名 |
### 3. 配送業者への追加フィールド(`dtb_deliv`)(任意)
| カラム名 | 型 | Default | Nullable | Comment |
|----------|------|---------|----------|---------|
| `estimated_delivery_days_min` | integer | | true | 最短お届け日数 |
| `estimated_delivery_days_max` | integer | | true | 最長お届け日数 |
| `carrier_code` | text | | true | 配送業者コード |
---
## データ形式のマッピング対応
### 住所フォーマット変換(EC-CUBE 2系 → UCP)
EC-CUBE 2系は電話番号・郵便番号が分割されているため、結合処理が必要
| EC-CUBE 2 | UCP | 変換処理 |
|-----------|-----|----------|
| `order_name01` + `order_name02` | `recipient_name` | 姓名結合 |
| `order_zip01` + `order_zip02` または `order_zipcode` | `postal_code` | 結合または海外対応フィールド使用 |
| `mtb_pref.name` (via `order_pref`) | `region` | 都道府県名取得 |
| `order_addr01` | `locality` | 市区町村 |
| `order_addr02` | `address1`, `address2` | 番地・建物名 |
| `mtb_country.iso_code` (via `order_country_id`) | `country` | ISO 3166-1 alpha-2 |
| `order_tel01` + `order_tel02` + `order_tel03` | `phone` | 電話番号結合 |
### 購入者情報マッピング
| EC-CUBE 2 | UCP | 備考 |
|-----------|-----|------|
| `order_name01` | `last_name` | 姓 |
| `order_name02` | `first_name` | 名 |
| `order_email` | `email` | メールアドレス |
| `order_tel01`-`order_tel03` | `phone` | 電話番号(結合) |
### 金額単位変換(センス/マイナー単位)
UCPでは金額をマイナー単位(整数)で表現する。
| 通貨 | 補助単位 | 変換例 |
|------|----------|--------|
| USD(米ドル) | セント | $10.50 → `1050` |
| EUR(ユーロ) | セント | €10.50 → `1050` |
| **JPY(日本円)** | **なし** | ¥1000 → `1000`(変換不要) |
**日本円は「ゼロデシマル通貨」のため、基本的に変換不要(numeric → int のキャストのみ)**
```php
// JPY専用のシンプルな実装
$ucpAmount = (int) round($order['total']);
// 多通貨対応の場合
function toMinorUnits($amount, $currency = 'JPY') {
$decimals = array(
'JPY' => 0, 'KRW' => 0, 'TWD' => 0, // ゼロデシマル通貨
);
$dec = isset($decimals[$currency]) ? $decimals[$currency] : 2;
if ($dec === 0) {
return (int) round($amount);
}
return (int) round($amount * pow(10, $dec));
}
```
---
## 実装タスク
### Phase 1: 基盤構築
- [ ] `dtb_checkout_session` テーブル作成(マイグレーションSQL)
- [ ] `dtb_baseinfo` へのUCP関連カラム追加
- [ ] `SC_Helper_CheckoutSession` ヘルパークラス作成
### Phase 2: API実装
- [ ] `LC_Page_Api_CheckoutSession` クラス作成
- [ ] `POST /checkout-sessions` エンドポイント実装
- [ ] `PUT /checkout-sessions/{id}` エンドポイント実装
- [ ] `POST /checkout-sessions/{id}/complete` エンドポイント実装
- [ ] 既存 `SC_Helper_Purchase` との連携
### Phase 3: 変換・サービス層
- [ ] 住所フォーマット変換関数実装(電話番号・郵便番号結合)
- [ ] 金額単位変換関数実装
- [ ] 税金・送料再計算ロジック実装
### Phase 4: 品質・セキュリティ
- [ ] リクエストバリデーション実装(`SC_CheckError` 活用)
- [ ] エラーハンドリング(UCPプロトコル準拠のJSON形式)
- [ ] API認証・セキュリティ対策
- [ ] CSRF対策
### Phase 5: テスト・運用
- [ ] PHPUnit テスト作成
- [ ] API仕様書作成
- [ ] Google Merchant設定手順ドキュメント
---
## EC-CUBE 4系との実装差異
| 項目 | EC-CUBE 2系 | EC-CUBE 4系 |
|------|-------------|-------------|
| **アーキテクチャ** | 手続き型・LC_Page ベース | Symfony Controller ベース |
| **ORM** | SC_Query(生SQL) | Doctrine ORM |
| **購入処理** | SC_Helper_Purchase | PurchaseFlow(プロセッサパターン) |
| **バリデーション** | SC_CheckError | Symfony Validator |
| **セッション管理** | $_SESSION 直接操作 | Symfony Session |
| **JSONレスポンス** | 手動echo | JsonResponse |
| **電話番号** | 3分割(tel01, tel02, tel03) | 1フィールド(phone_number) |
| **郵便番号** | 2分割 or 海外対応1フィールド | 1フィールド(postal_code) |
| **受注一時情報** | dtb_order_temp テーブル | pre_order_id による管理 |
### 既存クラスの活用
| 既存クラス | 用途 |
|-----------|------|
| `SC_Helper_Purchase` | 受注処理(registerOrderComplete, registerOrder等) |
| `SC_Helper_Delivery` | 配送業者・送料取得 |
| `SC_Helper_TaxRule` | 税率計算 |
| `SC_CartSession` | カート操作 |
| `SC_CheckError` | バリデーション |
| `SC_Response` | レスポンス出力 |
---
## 技術的考慮事項
1. **既存購入フローとの共存**: 既存の `LC_Page_Shopping_*` による購入フローとUCP経由の購入フローの統合
2. **受注一時テーブル活用**: `dtb_order_temp` を活用したセッション管理の検討
3. **トランザクション管理**: 受注完了時の複合トランザクション(dtb_order, dtb_order_detail, dtb_shipping, dtb_shipment_item)
4. **在庫管理**: `SC_Helper_Purchase::registerOrderComplete()` 内の在庫減少処理との連携
5. **ポイント管理**: `add_point`, `use_point` との整合性
6. **セッション有効期限**: `dtb_checkout_session.expires_at` による期限切れ処理
7. **クリーンアップ**: 期限切れセッションの定期削除(cron)
---
## 参考リソース
- [Google UCP ドキュメント](https://developers.google.com/merchant/ucp/guides/checkout/native?hl=ja)
- [EC-CUBE 4系 UCP Issue](https://github.com/EC-CUBE/ec-cube/issues/6574)
- 既存実装参考:
- `data/class/helper/SC_Helper_Purchase.php`
- `data/class/pages/shopping/LC_Page_Shopping_Complete.php`
- `data/class/SC_CartSession.php`
- テーブル定義:
- `docs/database-schema/public.dtb_order.md`
- `docs/database-schema/public.dtb_shipping.md`
- `docs/database-schema/public.dtb_baseinfo.md`
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.