手作業
紙の発注書をスマートフォンで撮影する
FAX・紙で届いた発注書をスマートフォンで撮影します。シャッターボタンをタップしてください。
発 注 書
発注日:2026/10/06
紀の川青果㈱
| カットキャベツ | 200袋 |
| 白菜カット | 150袋 |
| 千切りにんじん | 100袋 |
納期:10/8 午前中
シャッターボタンをクリックして撮影してください
撮影(またはスキャン)が担当者の最初の手作業です。
撮影完了。次は Google ドライブの共有フォルダにアップロードします。
手作業
共有フォルダ(FAX受注)にアップロードする
撮影した画像・PDFを「共有フォルダ > DBG > FAX受注」に保存します。手作業はここで終わりです。
📄
発注書_南紀青果_1003.pdf
📄
発注書_オークワ橋本店_1005.jpg
発注書_紀の川青果_1006.jpg(撮影済み)
🤖
GAS が新ファイルを検知しました。 ここから自動で処理が進みます。
担当者の手作業はここまでです。 以降は GAS と AI が自動で処理します。
自動処理
GAS 起動 → Gemini が発注書を自動読み取り
GAS がファイルを検知し、Gemini API に画像・PDF を送信。AI が発注書の内容をテキスト化します。所要時間:約3〜5分。
実行ログ
✓ 発注書_紀の川青果_1006.jpg を検知
✓ Gemini API に画像データを送信
✓ 画像解析完了(2.8秒)
→ 読み取り結果をスプレッドシートに転記中...
Gemini 読み取り結果
2026年10月6日
信頼度:高紀の川青果 株式会社
信頼度:高2026年10月8日
信頼度:高要確認
読み取り不可| 商品名 | 数量 | 単位 | 信頼度 |
|---|---|---|---|
| カットキャベツ(200g) | 200 | 袋 | 高 |
| 白菜カット(300g) | 150 | 袋 | 高 |
| 千切りにんじん(150g) | 100 | 袋 | 高 |
特記事項:午前中納品希望・冷蔵便指定
「要確認」の箇所だけ担当者がスプレッドシートで修正します。
自動処理
スプレッドシートに自動転記される
読み取ったデータが FAX 受注管理シートに自動転記されます。新規データはハイライトされます。
| 受付日 | 得意先 | 商品名 | 数量 | 単位 | 納期 | 特記 | 状態 | |
|---|---|---|---|---|---|---|---|---|
| 1 | 10/3 | 南紀青果 | きざみネギパック | 300 | 袋 | 10/5 | 処理済 | |
| 2 | 10/6 | 紀の川青果 | カットキャベツ(200g) | 200 | 袋 | 10/8 | 冷蔵便 | ★新規 |
| 3 | 10/6 | 紀の川青果 | 白菜カット(300g) | 150 | 袋 | 10/8 | 冷蔵便 | ★新規 |
| 4 | 10/6 | 紀の川青果 | 千切りにんじん(150g) | 100 | 袋 | 10/8 | 冷蔵便 | ★新規 |
エラー箇所は赤字で表示されます。担当者は確認・修正するだけです。
確認・出力
作業指示書を確認して出力する
内容を確認後、「PDF 出力」ボタンで指示書 PDF を生成します。
作業指示書
出力日時:2026年10月6日 14:25 / 自動生成
| 商品名 | 数量 | 保管場所 |
|---|---|---|
| カットキャベツ(200g) | 200袋 | 第1冷蔵加工室 |
| 白菜カット(300g) | 150袋 | 第1冷蔵加工室 |
| 千切りにんじん(150g) | 100袋 | 第2冷蔵加工室 |
特記事項:午前中納品希望・冷蔵便指定
完了。 撮影→アップロードの2ステップだけで、作業指示書まで自動生成されました。
実装ガイド:FAX受注フロー(Gemini OCR + GAS)
スプレッドシート列定義
| 列 | 項目名 | 型 | 備考 |
|---|---|---|---|
| A | 受付日 | 日付 | GAS自動入力 |
| B | 得意先名 | テキスト | Gemini読み取り値 |
| C | 商品名 | テキスト | Gemini読み取り値 |
| D | 数量 | 数値 | Gemini読み取り値 |
| E | 単位 | テキスト | 袋/本/ケース |
| F | 納期 | 日付 | 不明なら「要確認」 |
| G | 特記事項 | テキスト | 冷蔵便・時間指定など |
| H | 状態 | テキスト | GASが「★新規」と入力 |
| I | 元ファイル名 | テキスト | GAS自動入力(トレース用) |
Gemini OCR プロンプト
あなたは発注書の画像を読み取るOCRアシスタントです。
以下の発注書を解析し、必ずJSON形式のみで回答してください(説明・コードブロック不要)。
{
"発注日": "YYYY/MM/DD 形式 または null",
"得意先名": "会社名 または null",
"担当者名": "名前 または null(読み取れない場合)",
"納期": "YYYY/MM/DD 形式 または null",
"特記事項": "配送指定・備考など または null",
"商品リスト": [
{
"商品名": "商品名(規格・サイズも含む)",
"数量": 数値(整数・文字列不可),
"単位": "袋/本/ケース/枚 など"
}
]
}
【必ず守ること】
・読み取れない・不明な項目は必ず null とする
・数量は数値型(例: 100)で出力し、文字列にしないこと
・日付は YYYY/MM/DD 形式に統一すること
・JSON のみ返答すること(``` や説明文を含めない)
GAS コード(完全版)
// ===================================================
// FAX受注 自動処理スクリプト
// Gemini Vision API を使って発注書画像を自動読み取り
// ===================================================
const CONFIG = {
FAX_FOLDER_ID: '★ FAX受注フォルダのID(DriveのURLから取得)',
SHEET_ID: '★ FAX受注管理スプレッドシートのID(URLから取得)',
SHEET_NAME: 'FAX受注管理',
GEMINI_API_KEY: '★ Google AI Studio で取得した APIキー',
GEMINI_MODEL: 'gemini-1.5-flash',
};
const PROMPT = `あなたは発注書の画像を読み取るOCRアシスタントです。
以下の発注書を解析し、必ずJSON形式のみで回答してください(説明不要)。
{
"発注日": "YYYY/MM/DD または null",
"得意先名": "会社名 または null",
"担当者名": "名前 または null",
"納期": "YYYY/MM/DD または null",
"特記事項": "テキスト または null",
"商品リスト": [{"商品名": "名前", "数量": 数値, "単位": "袋/本/ケース等"}]
}
読み取れない項目はnull。JSONのみ返答。`;
/**
* ① メイン処理(トリガーで5分ごとに実行)
*/
function checkFaxFolder() {
const folder = DriveApp.getFolderById(CONFIG.FAX_FOLDER_ID);
const files = folder.getFiles();
const sheet = SpreadsheetApp
.openById(CONFIG.SHEET_ID)
.getSheetByName(CONFIG.SHEET_NAME);
while (files.hasNext()) {
const file = files.next();
if (file.getName().includes('_処理済み')) continue;
try {
const data = callGeminiOCR(file);
writeToSheet(sheet, data, file.getName());
file.setName(file.getName() + '_処理済み');
console.log('処理完了:', file.getName());
} catch (e) {
console.error('エラー:', file.getName(), e.message);
}
}
}
/**
* ② Gemini Vision API 呼び出し → JSONを返す
*/
function callGeminiOCR(file) {
const blob = file.getBlob();
const base64 = Utilities.base64Encode(blob.getBytes());
const mimeType = blob.getContentType();
const payload = {
contents: [{
parts: [
{ text: PROMPT },
{ inline_data: { mime_type: mimeType, data: base64 } }
]
}]
};
const url = `https://generativelanguage.googleapis.com/v1beta/models/`
+ `${CONFIG.GEMINI_MODEL}:generateContent?key=${CONFIG.GEMINI_API_KEY}`;
const res = UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload),
});
const text = JSON.parse(res.getContentText())
.candidates[0].content.parts[0].text;
return JSON.parse(text);
}
/**
* ③ スプレッドシートへの書き込み(商品ごとに1行)
*/
function writeToSheet(sheet, data, fileName) {
const today = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'MM/dd');
data.商品リスト.forEach(item => {
sheet.appendRow([
today,
data.得意先名 || '要確認',
item.商品名,
item.数量,
item.単位 || '',
data.納期 || '要確認',
data.特記事項 || '',
'★新規',
fileName,
]);
});
}
GAS トリガー設定手順
- GAS エディタ(script.google.com)を開き、上記コードを貼り付ける
- CONFIG の各 ID を実際の値に書き換える
フォルダID:DriveのURLの「folders/」以降 / シートID:スプレッドシートURLの「/d/」以降 - 左メニューの「トリガー(時計アイコン)」→「トリガーを追加」
- 関数:checkFaxFolder / イベント:時間主導型 → 5分おき で保存
- 初回のみ「権限を確認」ダイアログを許可する
Gemini への質問テンプレート:
「GASでDriveの特定フォルダを監視し、新しい画像が追加されたらGemini APIで解析してスプレッドシートに書き込むコードを書いてください。CONFIG変数:[CONFIGの内容を貼り付け]」
「GASでDriveの特定フォルダを監視し、新しい画像が追加されたらGemini APIで解析してスプレッドシートに書き込むコードを書いてください。CONFIG変数:[CONFIGの内容を貼り付け]」
手作業
得意先から Excel 受注書を受け取る
各得意先から届く Excel 形式の受注書を受け取ります。得意先ごとにフォーマットが異なっていても自動で読み取ります。
オークワ各店舗から受信した Excel 受注書(クリックで選択)
オークワ和歌山店
受注書_1006.xlsx
✓ 選択中
オークワ奈良店
order_20261006.xlsx
✓ 選択中
オークワ東海店
発注_10月.xlsx
✓ 選択中
得意先ごとに Excel のフォーマットが違っていても、GAS が自動で統一して取り込みます。
Excel ファイルを受け取ってフォルダに保存するだけで OK です。
手作業
指定フォルダ(帳合受注)に保存する
「共有フォルダ > DBG > 帳合受注」に Excel ファイルを保存します。手作業はここで終わりです。
🤖
GAS が 3 件を検知しました。 自動で取り込み・集計を開始します。
担当者の手作業はここまでです。
自動処理
GAS が各受注書を取り込み・統合集計する
フォーマットが異なる 3 社分の Excel を読み込み、商品ごとに統合集計します。
山田スーパー
処理中
田中マート
処理中
鈴木商店
処理中
実行ログ
✓ オークワ和歌山店_受注書_1006.xlsx 読み込み完了
✓ オークワ奈良店_order_20261006.xlsx 読み込み完了
✓ オークワ東海店_発注_10月.xlsx 読み込み完了
✓ 商品マスターと照合完了
✓ 得意先別・商品別に統合集計完了
→ 集計シートへの書き込み完了
3 社分のデータを統合集計しました。内容を確認してください。
確認
集計シートで数量・内容を確認する
得意先別・商品別の受注数量が自動集計されています。確認後、「発注書作成」ボタンを押します。
| 商品名 | 和歌山店 | 奈良店 | 東海店 | 合計数量 | 仕入れ先 |
|---|---|---|---|---|---|
| きざみネギパック(100g) | 400 | 280 | 320 | 1,000袋 | 淡路島ファーム |
| ケン付大根(刺身用) | 250 | – | 180 | 430袋 | 淡路島ファーム |
| 炒め物野菜ミックス(200g) | – | 350 | 290 | 640袋 | 三重産直センター |
| グリーンサラダパック | 200 | 150 | – | 350袋 | 三重産直センター |
数量に誤りがあればここで修正できます。確認後ボタンを押すだけです。
自動処理
仕入れ先別の発注書が自動生成される
複数得意先の注文を合算した仕入れ先ごとの発注書が自動生成されます。PDF 出力・メール送信も対応。
淡路島ファーム 発注書
発注日:2026年10月6日
| 商品名 | 数量 |
|---|---|
| きざみネギパック(100g) | 1,000袋 |
| ケン付大根(刺身用) | 430袋 |
合計 1,430袋
三重産直センター 発注書
発注日:2026年10月6日
| 商品名 | 数量 |
|---|---|
| 炒め物野菜ミックス(200g) | 640袋 |
| グリーンサラダパック | 350袋 |
合計 990袋
完了。 オークワ 3 店舗分の受注 Excel をフォルダに保存するだけで、仕入れ先 2 社への発注書が自動生成されました。
実装ガイド:帳合受注フロー(Excel自動集計 GAS)
商品マスターシート 列定義
| 列 | 項目名 | 記入例 | 備考 |
|---|---|---|---|
| A | 商品名(キー) | きざみネギパック | Excelの商品名と前方一致で照合 |
| B | 規格 | 100g | 参考情報 |
| C | 仕入れ先 | 淡路島ファーム | 発注書の宛先として使用 |
| D | 単位 | 袋 | 集計・発注書に使用 |
商品マスターは事前にすべての取扱商品を登録しておくこと。登録外の商品は「要確認」として集計されます。
GAS コード(完全版)
// ===================================================
// 帳合受注 自動集計スクリプト
// Excelをフォルダに入れるだけで仕入れ先別に集計・発注書生成
// ===================================================
const CHOGAI = {
FOLDER_ID: '★ 帳合受注フォルダのID',
SHEET_ID: '★ 帳合集計スプレッドシートのID',
SUMMARY_SHEET: '帳合集計',
MASTER_SHEET: '商品マスター',
PO_SHEET: '発注書',
};
/** ① メイン処理(トリガーで5分ごとに実行) */
function processChogaiFiles() {
const folder = DriveApp.getFolderById(CHOGAI.FOLDER_ID);
const ss = SpreadsheetApp.openById(CHOGAI.SHEET_ID);
const master = ss.getSheetByName(CHOGAI.MASTER_SHEET)
.getDataRange().getValues();
const summary = ss.getSheetByName(CHOGAI.SUMMARY_SHEET);
const files = folder.getFiles();
while (files.hasNext()) {
const file = files.next();
const name = file.getName();
if (!name.match(/\.xlsx?$/i)) continue;
if (name.includes('_処理済み')) continue;
try {
const rows = readExcelFile(file);
aggregateRows(summary, rows, master, name);
file.setName(name + '_処理済み');
console.log('集計完了:', name);
} catch (e) {
console.error('エラー:', name, e.message);
}
}
generatePurchaseOrders(ss);
}
/** ② ExcelをGoogleスプレッドシートに変換して読み込む */
function readExcelFile(file) {
const tempId = Drive.Files.copy(
{ title: '_tmp_' + file.getName(), mimeType: MimeType.GOOGLE_SHEETS },
file.getId()
).id;
const data = SpreadsheetApp.openById(tempId)
.getSheets()[0].getDataRange().getValues();
DriveApp.getFileById(tempId).setTrashed(true);
let hRow = 0;
for (let i = 0; i < Math.min(15, data.length); i++) {
if (data[i].some(c => /商品|品名|アイテム/.test(String(c)))) {
hRow = i; break;
}
}
const headers = data[hRow].map(c => String(c));
const nameCol = headers.findIndex(h => /商品|品名/.test(h));
const qtyCol = headers.findIndex(h => /数量|個数|発注数/.test(h));
const unitCol = headers.findIndex(h => /単位/.test(h));
return data.slice(hRow + 1)
.filter(row => row[nameCol] && Number(row[qtyCol]) > 0)
.map(row => ({
商品名: String(row[nameCol]).trim(),
数量: Number(row[qtyCol]),
単位: unitCol >= 0 ? String(row[unitCol]) : '袋',
}));
}
/** ③ 集計シートへの書き込み(商品マスターで仕入れ先を照合) */
function aggregateRows(sheet, rows, master, fileName) {
const today = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'MM/dd');
const store = extractStoreName(fileName);
rows.forEach(row => {
const m = master.find(r => row.商品名.startsWith(String(r[0]).substring(0, 4)));
const supplier = m ? m[2] : '要確認';
const existing = findRowByItem(sheet, row.商品名);
if (existing > 0) {
const col = getStoreColumn(sheet, store);
const cell = sheet.getRange(existing, col);
cell.setValue((Number(cell.getValue()) || 0) + row.数量);
} else {
sheet.appendRow([row.商品名, row.単位, supplier, today, 0, 0, 0, row.数量]);
}
});
}
/** ④ 仕入れ先別の発注書シートを自動生成・更新 */
function generatePurchaseOrders(ss) {
const summary = ss.getSheetByName(CHOGAI.SUMMARY_SHEET);
const poSheet = ss.getSheetByName(CHOGAI.PO_SHEET) || ss.insertSheet(CHOGAI.PO_SHEET);
const data = summary.getDataRange().getValues();
poSheet.clearContents();
poSheet.appendRow(['仕入れ先', '商品名', '数量', '単位', '発注日']);
const today = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd');
data.slice(1).forEach(row => {
const total = (row[4] || 0) + (row[5] || 0) + (row[6] || 0);
if (total > 0) {
poSheet.appendRow([row[2], row[0], total, row[1], today]);
}
});
}
GAS トリガー設定手順
- GAS エディタで新しいプロジェクトを作成し、上記コードを貼り付ける
- 「サービス」→「Drive API」を追加する(Excel読み込みに必要)
- CHOGAI の各 ID を実際の値に書き換える
- 「トリガー」→「トリガーを追加」→ 関数:processChogaiFiles / タイプ:5分おきタイマー で保存
- 初回のみ権限を許可する
よくある質問
| 質問 | 対処法 |
|---|---|
| Excelのフォーマットが店舗ごとに違う | ヘッダー行の自動検出ロジックが対応。「商品」「品名」を含む行を自動で探します |
| 処理完了をSlack/LINEに通知したい | UrlFetchApp.fetch() でWebhook URLにPOSTするだけで通知できます |
| マスターにない商品が来た場合 | 「要確認」として集計。GmailApp.sendEmail() でメール通知も追加可能 |