Shopify、楽天、Qoo10の各ECサイトとGoogleスプレッドシート間での在庫同期を自動化するシステムです。注文確認や注文タグ「DD日」をもって売れたと判断し、自動実行で在庫を同期します。1時間に1回の定期実行を想定しています。
在庫同期/
├── inventory_sync_allinone.py # メインスクリプト(全機能統合版)
├── app.py # Webアプリケーション(Flask)
├── requirements.txt # Python依存関係
├── README.md # このファイル
├── config/ # 設定ファイル
│ ├── .env # 環境変数設定ファイル
│ └── credentials.json # Google Sheets API認証情報
├── data/ # データファイル
│ └── inventory_sync.db # SQLiteデータベース(注文処理履歴等)
├── logs/ # ログファイル
│ └── inventory_sync.log # 実行ログ
├── templates/ # Webアプリケーション用HTMLテンプレート
│ ├── base.html # ベーステンプレート
│ ├── index.html # メインページ
│ ├── logs.html # ログ表示ページ
│ ├── database.html # データベース表示ページ
│ └── readme.html # 仕様書表示ページ
└── archive/ # アーカイブファイル(開発段階のファイル)
├── bat/ # バッチファイル(開発用)
├── docs/ # API仕様書等のドキュメント
├── logs/ # 過去のログファイル
├── debug_*.py # デバッグ用スクリプト
├── fix_*.py # 修正用スクリプト
├── check_*.py # チェック用スクリプト
├── inventory_*.py # 開発中の古いバージョン
└── product_identification_report.py # 商品識別レポート生成
# 仮想環境を作成
python3 -m venv venv
# 仮想環境をアクティベート(macOS/Linux)
source venv/bin/activate
# 仮想環境をアクティベート(Windows)
venv\Scripts\activate
# 仮想環境がアクティブな状態で実行
pip install --upgrade pip
pip install -r requirements.txt
config/.envファイルに以下の設定が必要です:
# 環境設定
ENVIRONMENT=production # test または production
# Lark通知設定
LARK_WEBHOOK_URL=https://your-webhook-url
# Googleスプレッドシート設定
PRODUCTION_SPREADSHEET_URL=https://docs.google.com/spreadsheets/d/...
PRODUCTION_SHEET_NAME=出荷予定日別集計
TEST_SPREADSHEET_URL=https://docs.google.com/spreadsheets/d/...
TEST_SHEET_NAME=出荷予定日別集計_テスト
# 楽天API設定
RAKUTEN_SERVICE_SECRET=your-service-secret
RAKUTEN_LICENSE_KEY=your-license-key
RAKUTEN_TEST_SERVICE_SECRET=your-test-service-secret
RAKUTEN_TEST_LICENSE_KEY=your-test-license-key
# Shopify店舗設定
ARTGRAPH_SHOP=your-shop.myshopify.com
ARTGRAPH_TOKEN=your-token
PHOTOPRI_SHOP=your-shop.myshopify.com
PHOTOPRI_TOKEN=your-token
QOO_SHOP=your-shop.myshopify.com
QOO_TOKEN=your-token
# テスト環境用(ENVIRONMENT=testの場合)
ARTGRAPH_TEST_SHOP=your-test-shop.myshopify.com
ARTGRAPH_TEST_TOKEN=your-test-token
PHOTOPRI_TEST_SHOP=your-test-shop.myshopify.com
PHOTOPRI_TEST_TOKEN=your-test-token
QOO_TEST_SHOP=your-test-shop.myshopify.com
QOO_TEST_TOKEN=your-test-token
config/credentials.jsonファイルにGoogle Sheets APIのサービスアカウント認証情報を配置してください。
# 仮想環境をアクティベート
source venv/bin/activate
# Webアプリケーションを起動
python app.py
# または
./run_web.sh
ブラウザで http://localhost:8080 にアクセスしてWebインターフェースを使用
# 仮想環境をアクティベート
source venv/bin/activate
# 在庫同期を実行
python inventory_sync_allinone.py
# 1時間に1回実行
0 * * * * cd /path/to/在庫同期 && python inventory_sync_allinone.py
実行中は他の操作をブロック
ロールバックボタン
確認ダイアログで誤操作を防止
ログファイル確認
ログレベルの説明付き
データベース確認
テーブル説明付き
仕様書確認
inventory_sync_allinone.pyこの1つのスクリプトで以下の全機能を実行できます:
楽天variant_title対応: 正確な色情報抽出
在庫調整
部材条件マッピングベース: サイズ×色の組み合わせによる正確な在庫調整
集計・出力
小物印刷/大物印刷の分類集計
在庫突合・監視
差分検出とログ出力
通知・報告機能
詳細ログファイルへの記録
ロールバック機能
.env - 環境変数設定ファイル(APIキー等の機密情報)credentials.json - Google Sheets API認証情報inventory_sync.db - SQLiteデータベース(注文処理履歴等)inventory_sync.log - 実行ログ(継続的に追記される)注意: データベースファイルとログファイルは既存のファイルを使用します。初回実行時は自動的に作成されますが、既存の履歴を保持するため、これらのファイルは削除しないでください。
=== 在庫同期開始 ===
本番環境のストア設定を使用
本番環境の楽天API認証情報を使用
未処理注文を検出: Shopify X件, 楽天 Y件
処理した注文数: Z件
[在庫調整対象] 店舗名: 注文番号 - 商品タイプ サイズ 色 x数量
[削除済み商品除外] 店舗名: 注文番号 - 削除済み
=== 部材条件マッピングベース在庫調整開始 ===
[在庫更新] シート名: 商品タイプ サイズ 在庫 旧値 → 新値(セル位置): 成功/失敗
=== 部材条件マッピングベース在庫調整完了 ===
=== スプレッドシート在庫を楽天に反映します ===
=== 楽天在庫反映 完了 ===
=== スプレッドシート在庫をShopifyに反映します ===
=== Shopify在庫反映 完了 ===
楽天注文出荷状態確認エラー (注文番号): エラー内容
Google Sheets認証エラー: エラー内容
出荷済み注文を削除: 店舗名 - 注文ID
出荷済み注文の削除完了: X件
📊 在庫調整結果報告
⏰ 実行時刻: 2024年09月20日 13:30
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
調整日時: 2024年09月20日 13:30
調整対象部材数: 3種類
チャイナフレーム(チェリーウッド) A4サイズ
調整前: 50個 → 調整後: 47個
消費数量: 3個
調整理由: 部材消費(注文処理による)
関連注文:
注文番号#1001: "チェリーウッド チャイナフレーム (A4(チェリーウッド))" (A4サイズ)
キャンバス木枠(ブラックウォルナット) F4サイズ
調整前: 30個 → 調整後: 28個
消費数量: 2個
調整理由: 部材消費(注文処理による)
関連注文:
注文番号#1003: "ブラックウォルナット キャンバス木枠 (F4(ブラックウォルナット))" (F4サイズ)
📊 在庫調整結果報告
⏰ 実行時刻: 2024年09月20日 13:30
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
調整日時: 2024年09月20日 13:30
調整対象部材数: 0種類
調整対象の部材がありませんでした。
在庫同期処理は正常に完了しました。
# variant_titleから色情報を抽出
if 'チェリーウッド' in color_info or 'チェリー' in color_info:
color = 'チェリーウッド'
elif 'ビルマチーク' in color_info or 'ビルマ' in color_info:
color = 'ビルマチーク'
elif 'ブラックウォルナット' in color_info or 'ウォルナット' in color_info:
color = 'ブラックウォルナット'
elif 'ブラウン' in color_info:
color = 'ブラウン'
elif 'ナチュラル' in color_info:
color = 'ナチュラル'
# variant_titleからサイズ情報を抽出
size_patterns = ['A5', 'A4', 'A3', 'A2', 'A1', 'B5', 'B4', 'B3', 'B2', 'B1',
'300*300', '600*600', 'F0', 'F3', 'F4', 'F6', 'F8', 'F10', 'F15', 'F20', '2L']
for pattern in size_patterns:
if pattern in variant_title:
size = pattern
break
システムはmaterial_conditionsテーブルで部材条件を管理し、在庫調整を行います:
# 部材条件の確認
sqlite3 inventory_sync.db "SELECT material_name, store_name, condition_type, condition_value FROM material_conditions;"
-- キャンバス木枠の条件
キャンバス木枠|PHOTOPRI|product_name_pattern|キャンバス木枠張り|現在庫|51|70
キャンバス木枠|Qoo|product_name_pattern|似顔絵キャンバス|現在庫|51|70
キャンバス木枠|artgraph|product_type|Canvas.|現在庫|51|70
キャンバス木枠|artgraph|product_name_pattern|似顔絵キャンバス|現在庫|51|70
-- チャイナフレームの条件
チャイナフレーム|artgraph|product_type|Frame.|現在庫|51|70
チャイナフレーム|artgraph|product_name_pattern|Poster.|現在庫|51|70
チャイナフレーム|Qoo|product_id_and_variant|8913272406326,8877398229302|現在庫|51|70
チャイナフレーム|rakuten|sku_info_extraction|A1,A2,A3,A4,A5,B1,B2,B3,B4,B5,チェリーウッド,ビルマチーク,ブラックウォルナット|在庫管理|1|100
注意: チャイナフレームの部材条件は、PHOTOPRIストアには現在設定されていません。
楽天のチャイナフレーム部材条件はsku_info_extractionタイプを使用し、以下の特徴があります:
variant_titleから色とサイズを抽出し、チャイナフレームの色(チェリーウッド、ビルマチーク、ブラックウォルナット)とサイズ(A1-A5, B1-B5)の組み合わせで判定在庫管理シートの1-100行で管理修正内容(2025年9月24日): - 問題: 条件値の解析ロジックが間違っており、最後に見つかった値のみを期待値として設定していた - 修正: 条件値から期待されるサイズと色のリストを正しく解析し、実際のサイズ・色が期待されるリストに含まれているかチェックするように変更 - 効果: 楽天の注文でチャイナフレームとして認識された商品が部材条件とマッチし、在庫調整が正常に実行されるようになります
この設定により、楽天の注文でチャイナフレームとして認識された商品が部材条件とマッチし、在庫調整が正常に実行されるようになります。
sku_info_extraction: variant_titleから色情報を抽出(楽天推奨)sku_pattern: SKUパターンベースの抽出product_name_pattern: 商品名パターンベースの抽出product_name_and_variant: 商品名とバリアント情報ベースの抽出product_type: 商品タイプベースの抽出(artgraph推奨)product_id_and_variant: 商品IDとバリアント情報ベースの抽出(Qoo推奨)楽天:
1. sku_info_extractionタイプ(最優先)
2. sku_patternタイプ
3. product_name_patternタイプ
4. その他のタイプ
artgraph:
1. product_typeタイプ(最優先)
2. product_name_patternタイプ
3. その他のタイプ
PHOTOPRI:
1. product_name_patternタイプ(最優先)
2. その他のタイプ
Qoo:
1. product_id_and_variantタイプ(最優先)
2. product_name_patternタイプ
3. その他のタイプ
WOOD_FRAME_SKU_MAP = {
('ビルマチーク', 'A5'): 'r-sku00000001',
('ビルマチーク', 'A4'): 'r-sku00000002',
('ビルマチーク', 'A3'): 'r-sku00000003',
('ビルマチーク', 'A2'): 'r-sku00000004',
('ビルマチーク', 'A1'): 'r-sku00000005',
('ビルマチーク', 'B5'): 'r-sku00000006',
('ビルマチーク', 'B4'): 'r-sku00000007',
('ビルマチーク', 'B3'): 'r-sku00000008',
('ビルマチーク', 'B2'): 'r-sku00000009',
('ビルマチーク', 'B1'): 'r-sku00000010',
('チェリーウッド', 'A5'): 'r-sku00000011',
('チェリーウッド', 'A4'): 'r-sku00000012',
('チェリーウッド', 'A3'): 'r-sku00000013',
('チェリーウッド', 'A2'): 'r-sku00000014',
('チェリーウッド', 'A1'): 'r-sku00000015',
('チェリーウッド', 'B5'): 'r-sku00000016',
('チェリーウッド', 'B4'): 'r-sku00000017',
('チェリーウッド', 'B3'): 'r-sku00000018',
('チェリーウッド', 'B2'): 'r-sku00000019',
('チェリーウッド', 'B1'): 'r-sku00000020',
('ブラックウォルナット', 'A5'): 'r-sku00000021',
('ブラックウォルナット', 'A4'): 'r-sku00000022',
('ブラックウォルナット', 'A3'): 'r-sku00000023',
('ブラックウォルナット', 'A2'): 'r-sku00000024',
('ブラックウォルナット', 'A1'): 'r-sku00000025',
('ブラックウォルナット', 'B5'): 'r-sku00000026',
('ブラックウォルナット', 'B4'): 'r-sku00000027',
('ブラックウォルナット', 'B3'): 'r-sku00000028',
('ブラックウォルナット', 'B2'): 'r-sku00000029',
('ブラックウォルナット', 'B1'): 'r-sku00000030',
}
L_STAND_SKU_MAP = {
('ナチュラル', '2L'): 'r-sku00000001',
('ブラウン', '2L'): 'r-sku00000002',
('ダークブラウン', '2L'): 'r-sku00000002',
}
改善されたページネーション: すべてのページを確実に取得
出荷予定日算出
楽天: 確認日 + 2日
商品分類
チャイナフレーム、キャンバス木枠、L字スタンド、カレンダー&木製スタンドに分類
在庫調整
部材条件マッピングベース: サイズ×色の組み合わせで正確な在庫管理
集計出力
def extract_rakuten_size_and_color_from_sku(self, order_item):
# variant_titleからサイズと色を抽出
variant_title = order_item.get('variant_title', '')
# サイズ抽出
size_match = re.search(r'サイズ:([^(]+)\(', variant_title)
if size_match:
size = size_match.group(1).strip()
# 色抽出
color_match = re.search(r'カラー:([^\n]+)', variant_title)
if color_match:
color_info = color_match.group(1).strip()
# 色情報から色を決定
color = self.extract_color_from_info(color_info)
return size, color
# variant_titleに色情報がない場合は在庫調整対象外
if not color or color == 'None':
return None, None # 在庫調整対象外
ENVIRONMENT=testで実行してくださいconfig/フォルダに集約されており、セキュリティ上適切に管理してください.envファイルの認証情報を確認APIキーの有効期限を確認
スプレッドシートアクセスエラー
credentials.jsonファイルの存在確認Google Sheets APIの権限設定確認
在庫更新エラー
部材条件の設定確認
処理漏れ
variant_titleからの色情報抽出が正常か確認
部材条件エラー
# エラーログのみ確認
grep "ERROR" inventory_sync.log
# 在庫調整対象の確認
grep "在庫調整対象" inventory_sync.log
# 部材消費の確認
grep "部材消費" inventory_sync.log
# デバッグログの確認
grep "DEBUG" inventory_sync.log
# 条件マッチングの確認
grep "条件チェック" inventory_sync.log
# 処理済み注文の確認
sqlite3 inventory_sync.db "SELECT COUNT(*) FROM processed_orders WHERE DATE(processed_at) = '$(date +%Y-%m-%d)';"
# 在庫調整履歴の確認
sqlite3 inventory_sync.db "SELECT COUNT(*) FROM inventory_adjustments WHERE DATE(adjusted_at) = '$(date +%Y-%m-%d)';"
# 部材条件の確認
sqlite3 inventory_sync.db "SELECT material_name, store_name, condition_type, condition_value FROM material_conditions ORDER BY material_name, store_name;"
# 特定の部材の条件確認
sqlite3 inventory_sync.db "SELECT * FROM material_conditions WHERE material_name = 'チャイナフレーム';"
sqlite3 inventory_sync.db "SELECT * FROM material_conditions WHERE material_name = 'キャンバス木枠';"
新しいサイズ・色の組み合わせが必要な場合:
INSERT INTO material_conditions (
material_name, store_name, store_type, condition_type, condition_value,
sheet_name, sheet_row_start, sheet_row_end, sheet_col_type, sheet_col_size, sheet_col_stock
) VALUES (
'チャイナフレーム', 'rakuten', 'rakuten', 'sku_info_extraction', 'サイズ,色',
'現在庫', 51, 70, 'A', 'C', 'G'
);
1. データベースで直接修正
# 部材条件の確認
sqlite3 inventory_sync.db "SELECT * FROM material_conditions WHERE material_name = 'キャンバス木枠';"
sqlite3 inventory_sync.db "SELECT * FROM material_conditions WHERE material_name = 'チャイナフレーム';"
# 新しい条件の追加
sqlite3 inventory_sync.db "INSERT INTO material_conditions (material_name, store_name, store_type, condition_type, condition_value, sheet_name, sheet_row_start, sheet_row_end, sheet_col_type, sheet_col_size, sheet_col_stock) VALUES ('キャンバス木枠', '新しいストア', 'shopify', 'product_name_pattern', '新しいパターン', '現在庫', 51, 70, 'A', 'C', 'G');"
# 条件の更新
sqlite3 inventory_sync.db "UPDATE material_conditions SET condition_value = '新しいパターン' WHERE id = 1;"
# チャイナフレームの部材条件追加(推奨)
sqlite3 inventory_sync.db "INSERT INTO material_conditions (material_name, store_name, store_type, condition_type, condition_value, sheet_name, sheet_row_start, sheet_row_end, sheet_col_type, sheet_col_size, sheet_col_stock) VALUES ('チャイナフレーム', 'PHOTOPRI', 'shopify', 'product_name_pattern', 'チャイナフレーム', '現在庫', 51, 70, 'A', 'C', 'G');"
sqlite3 inventory_sync.db "INSERT INTO material_conditions (material_name, store_name, store_type, condition_type, condition_value, sheet_name, sheet_row_start, sheet_row_end, sheet_col_type, sheet_col_size, sheet_col_stock) VALUES ('チャイナフレーム', 'Qoo', 'shopify', 'product_name_pattern', 'チャイナフレーム', '現在庫', 51, 70, 'A', 'C', 'G');"
2. コードでの修正
# material_conditionsテーブルの構造
# id: 主キー
# material_name: 部材名(例:キャンバス木枠)
# store_name: ストア名(例:artgraph, PHOTOPRI, Qoo, rakuten)
# store_type: ストアタイプ(例:shopify, rakuten)
# condition_type: 条件タイプ(例:product_name_pattern, sku_info_extraction)
# condition_value: 条件値(例:Canvas., キャンバス木枠張り)
# sheet_name: シート名(例:現在庫)
# sheet_row_start: 開始行(例:51)
# sheet_row_end: 終了行(例:70)
# sheet_col_type: タイプ列(例:A)
# sheet_col_size: サイズ列(例:C)
# sheet_col_stock: 在庫列(例:G)
ウッド額縁SKUマッピング
# inventory_sync_allinone.py の WOOD_FRAME_SKU_MAP を修正
WOOD_FRAME_SKU_MAP = {
('色名', 'サイズ'): 'SKU番号',
# 例:
('ビルマチーク', 'A5'): 'r-sku00000001',
}
L字スタンドSKUマッピング
# inventory_sync_allinone.py の L_STAND_SKU_MAP を修正
L_STAND_SKU_MAP = {
('色名', 'サイズ'): 'SKU番号',
# 例:
('ナチュラル', '2L'): 'r-sku00000001',
}
条件マッチングのデバッグ
# process_shopify_order_materials メソッドにデバッグログを追加
logger.info(f"[DEBUG] 条件チェック開始: material_name='{condition.get('material_name', '')}', condition_type='{condition.get('condition_type', '')}', condition_value='{condition.get('condition_value', '')}'")
# match_material_condition メソッドにデバッグログを追加
logger.info(f"[DEBUG] Shopifyマッチング詳細: product_title='{product_title}', variant_title='{variant_title}', product_type='{product_type}'")
[在庫調整対象]: 在庫調整対象として認識された注文[在庫調整対象外]: 在庫調整対象外として処理された注文[部材消費]: 部材消費として記録された処理[在庫調整]: 実際の在庫調整処理[DEBUG]: デバッグ情報(条件マッチングの詳細など)# 条件マッチングの詳細確認
grep "条件チェック開始" inventory_sync.log
# キャンバス木枠の処理確認
grep "キャンバス木枠" inventory_sync.log
# 部材消費の確認
grep "部材消費" inventory_sync.log
問題が発生した場合は、以下の手順で確認してください:
logs/inventory_sync.log)の確認config/.env)data/inventory_sync.db)の整合性確認詳細な問題解決については、archive/docs/フォルダ内のドキュメントを参照してください。