本システムは、楽天市場(RMS)および Shopifyストア(artgraph、PHOTOPRI、Qoo)の注文情報を自動検知し、実在庫(Googleスプレッドシート)と各販売チャネル間の在庫数を同期・調整するシステムです。
システムの実行状況の確認、手動実行、ロールバック、ログやデータベースの監視をブラウザ上で行える管理画面です。
起動ポートは開発フォルダ共通のポート台帳(997_開発ナレッジ/04_PORT_MANAGEMENT.md)に従い 3142(024_在庫同期 に割り当てられた 3140-3149 ブロックの Web Frontend 用)を使用します。main/config/.env の PORT で指定し、本番サーバー(PM2 + nginx)も同じポートです。
# 1. 仮想環境のアクティベート
source .venv/bin/activate
# 2. カレントディレクトリをmainへ移動
cd main
# 3. アプリケーションの起動
python3 app.py
logs/inventory_sync.log)のリアルタイム表示・ダウンロードinventory_sync.db)の各テーブルデータの閲覧システムには Python 3.13 互換の仮想環境とパッケージが必要です。
# 1. 仮想環境の作成
python3 -m venv .venv
# 2. pandas等のインストール
.venv/bin/pip install pandas
.venv/bin/pip install -r main/requirements.txt flask markdown pytz
# 本番環境で実行
ENVIRONMENT=production .venv/bin/python main/inventory_sync_allinone.py
# テスト環境で実行
ENVIRONMENT=test .venv/bin/python main/inventory_sync_allinone.py
from main.inventory_sync_allinone import InventorySyncAllInOne
sync = InventorySyncAllInOne()
# A. 注文処理のみを実行
all_orders = sync.process_orders()
# B. 在庫調整処理を実行
sync.process_inventory_adjustment_v2(all_orders)
# C. 楽天在庫の反映のみを実行
sync.sync_sheet_to_rakuten_inventory()
# D. 楽天とスプレッドシートの在庫突合チェック
sync.compare_rakuten_and_sheet_inventory()
main/config/.env に各ストアのAPI接続情報を設定します。
# 実行環境設定 ("production" または "test")
ENVIRONMENT=production
# Shopify API 設定
ARTGRAPH_SHOP=your-shop.myshopify.com
ARTGRAPH_TOKEN=shpat_xxx
PHOTOPRI_SHOP=your-shop.myshopify.com
PHOTOPRI_TOKEN=shpat_xxx
QOO_SHOP=your-shop.myshopify.com
QOO_TOKEN=shpat_xxx
# 楽天市場 API 設定
RAKUTEN_SERVICE_SECRET=ESA xxx
RAKUTEN_LICENSE_KEY=SLxxx
# 通知設定 (Lark Webhook URL)
LARK_WEBHOOK_URL=https://open.larksuite.com/open-apis/bot/v2/hook/xxx
Googleスプレッドシートへのアクセスには、サービスアカウントキーファイルが必要です。
- 配置パス: main/config/credentials.json
- スコープ: https://www.googleapis.com/auth/spreadsheets
システムは、注文に特定商品が含まれているかを以下の優先順位とルールで判定し、スプレッドシート上の対応する在庫セルを減算します。
| 商品タイプ (部材) | 対象サイズ | 対象カラー | スプレッドシート該当行範囲 | 楽天管理番号 |
|---|---|---|---|---|
| チャイナフレーム (ウッド額縁) | A5, A4, A3, A2, A1, B5, B4, B3, B2, B1 | ビルマチーク, チェリーウッド, ブラックウォルナット | 3行目 〜 29行目 | p00002 (outletは除外) |
| キャンバス木枠 | A5〜B1, 300300, 600600, F0〜F20 | (なし) | 51行目 〜 70行目 | (なし) |
| L字スタンド | 2L (ハガキサイズは除外) | ブラウン, ナチュラル, ダークブラウン | 1行目 〜 100行目の動的検索 | photo_stand |
| カレンダー&木製スタンド | (なし) | (なし) | 1行目 〜 100行目の動的検索 | (なし) |
variant_title にカラーおよびサイズが含まれる場合 (最優先)product_title に「キャンバス木枠張り」「Canvas.」「似顔絵キャンバス」等を含む場合product_title に「フォトスタンド」「Postcard.」「L字スタンド」等を含む場合product_title に「卓上フォトカレンダー」等を含み、variant_title が「カレンダー&木製スタンド」の場合skuInfo (または variant_title) から「サイズ:XX」「カラー:XX」を直接抽出 (最優先)r-sku00000001 等のSKUマッピングテーブルに基づく判定p00002 などの管理番号の一致SQLite3データベース main/data/inventory_sync.db にて動作データとマッピング情報を管理しています。
processed_orders: 重複集計防止のため、処理済み注文番号・品目IDを管理します。inventory_adjustments: 在庫調整が行われた際の「変更前・変更後在庫数」「調整理由」等の履歴を保存します。material_conditions: 各ストア・商品ごとの「スプレッドシートの行・列位置」や「判定条件」をマッピングします。execution_logs: システムの起動、完了、エラー等の実行ステータスをログとして記録します。[!NOTE] データベースのDDLスキーマやメンテナンスコマンドの詳細は、別途 データベース構成引き継ぎ書.md を参照してください。
invalid_grant: account not found)本番サーバーおよびローカルでスプレッドシートアクセス時に以下が発生する場合、接続用サービスアカウントが無効化されています。
google.auth.exceptions.RefreshError: ('invalid_grant: Invalid grant: account not found', ...)
id-425@shopify-orderlist.iam.gserviceaccount.com)の代わりに新しいサービスアカウントを作成、または既存アカウントで新しい JSON キー を作成。main/config/credentials.json に上書き配置(本番サーバー側も同様)。# エラーログの抽出
grep "ERROR" main/logs/inventory_sync.log
# 実行状態・消費ログの確認
grep "在庫調整" main/logs/inventory_sync.log
grep "部材消費" main/logs/inventory_sync.log
本ドキュメントは、在庫同期システムが使用している SQLite3 データベースのテーブル設計、初期化方法、運用メンテナンス、および最新のシステム不具合改修内容について引き継ぎ用にまとめたものです。
main/data/inventory_sync.db/var/www/inventory-sync/data/inventory_sync.dbprocessed_orders (処理済み注文テーブル)sql
CREATE TABLE processed_orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id TEXT NOT NULL, -- 注文商品の一意なID (Shopifyは "注文ID_品目index", 楽天は "rakuten_注文ID_品目index")
store_name TEXT NOT NULL, -- ストア識別名 (artgraph, PHOTOPRI, Qoo, rakuten)
order_number TEXT, -- 注文番号 (表示用)
processed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 処理日時
shipping_date TEXT, -- 出荷予定日
order_type TEXT, -- 注文タイプ (大物印刷 / 小物印刷)
order_size TEXT, -- 商品サイズ (A4, A3, 2L等)
order_quantity INTEGER, -- 注文数量
order_color TEXT, -- カラー (チェリーウッド, ナチュラル等)
UNIQUE(order_id, store_name) -- 重複登録防止のユニーク制約
);inventory_adjustments (在庫調整履歴テーブル)sql
CREATE TABLE inventory_adjustments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
store_name TEXT NOT NULL, -- 調整対象ストア
product_id TEXT NOT NULL, -- 商品ID
variant_id TEXT, -- バリアントID / SKU
old_stock INTEGER, -- 調整前在庫数
new_stock INTEGER, -- 調整後在庫数
adjustment_reason TEXT, -- 調整理由 (例: "部材消費(注文処理による)")
adjusted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 調整日時
);execution_logs (システム実行ログテーブル)sql
CREATE TABLE execution_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
execution_type TEXT NOT NULL, -- 実行タイプ ("inventory_sync" 等)
status TEXT NOT NULL, -- 実行結果ステータス (started / completed / error)
message TEXT, -- 補足メッセージ・エラー詳細
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);material_conditions (部材条件マッピングテーブル)sql
CREATE TABLE material_conditions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
material_name TEXT NOT NULL, -- 部材名 (例: "キャンバス木枠", "L字スタンド")
store_name TEXT NOT NULL, -- ストア識別名
store_type TEXT NOT NULL, -- ストアタイプ (shopify / rakuten)
condition_type TEXT NOT NULL, -- 条件判定タイプ (product_type / product_name_pattern / product_id_and_variant等)
condition_value TEXT, -- 条件値 (例: "Canvas.", "L字スタンド")
condition_pattern TEXT, -- (予備) 判定パターン
sheet_name TEXT NOT NULL, -- スプレッドシートのシート名
sheet_row_start INTEGER, -- 対象セルの開始行
sheet_row_end INTEGER, -- 対象セルの終了行
sheet_col_type TEXT, -- タイプ(名称)列 (A列 等)
sheet_col_size TEXT, -- サイズ列 (C列 等)
sheet_col_stock TEXT, -- 在庫数列 (G列 等)
rakuten_manage_number TEXT, -- 楽天側の管理番号
rakuten_sku_pattern TEXT, -- 楽天側のSKUパターン
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);本番環境で発生していたデータの不整合・バグに対して以下の修正を行いました。
inventory_sync.db が自動生成され、過去データと最新データが分断される。BASE_DIR)とし、data/inventory_sync.db へのフルパスで固定接続するよう変更。order_id で重複判定していたため、同一注文内の別商品が再処理時にスキップされるか、二重引き下げになる現象が発生。f"{order['id']}_{item_index}" に完全統一。-1 や -2 などのマイナス値を記録し、楽天(0以上の整数のみ対応)との同期で値の乖離が発生。max(0, current_stock - qty) とし、負の値にならないよう制限。本番サーバーにログイン後、以下のコマンドで手動メンテナンスが可能です。
# データベースへ接続
sqlite3 /var/www/inventory-sync/data/inventory_sync.db
# 接続後の便利なメタコマンド
.tables -- テーブル一覧
.schema -- テーブルの作成スキーマ
.header on -- 出力時にヘッダー(列名)を表示
.mode column -- 出力を見やすいテーブル形式にする
長期間の運用でデータサイズが肥大化するのを防ぐため、30日以上前の実行ログ、および出荷後7日以上経過した重複チェック用データをクリーンアップします。
-- 30日以上前のログをクリーンアップ
DELETE FROM execution_logs WHERE executed_at < datetime('now', '-30 days');
-- 出荷予定日から7日以上経過した重複チェック用注文データの削除
DELETE FROM processed_orders WHERE shipping_date < DATE('now', '-7 days');
invalid_grant: account not found)本番サーバーのログにおいて、以下のようにスプレッドシート接続処理時に invalid_grant が発生した場合、Google Cloud Console 側で接続用サービスアカウントが無効化されています。
ERROR - 在庫情報取得エラー: ('invalid_grant: Invalid grant: account not found', ...)
config/credentials.json 内に記載されている client_email (サービスアカウント) が無効、もしくは削除されています。/var/www/inventory-sync/config/credentials.json を上書き差し替えします。