AppSheet初心者向け|経費精算アプリをゼロから構築する手順まとめ②
目次を表示/非表示
背景と目的
前回の記事「構築手順まとめ①」では、AppSheetで経費精算アプリのスプレッドシート設計と初期セットアップを行いました。
今回はその続編として、Step3「カラム設定」〜 Step5「テスト登録」までの操作編をまとめています。いよいよアプリとして動かす段階に入ってきます!
Step3|カラム設定とREFの定義
AppSheetはスプレッドシートのカラム名を読み込んだ際にデータ型を自動で読み取ってくれますが、意図しない場合もあるので、下記の通り設定しましょう。
以下の設定は手動で必ず見直しましょう。
 |
Appsheet データ型登録① |
 |
Appsheet データ型登録② |
- ID経費登録(登録テーブル):Key に設定(主キー)
→これは自動的に選ばれるはず。
 |
Appsheet データ型登録③ |
- ID経費明細(経費明細テーブル):Key に設定(主キー)
- 経費明細テーブルの、カラム「ID経費登録」:データType を REF にし、経費登録テーブルを参照
これにより、明細が「どの登録データに属するか」をAppSheet上で認識させることができ、フォームでも「親子関係」を構築できます。
💡補足|主キーと親キーの違い
経費明細TBLを例とすると
- 主キー(Key):そのレコードを一意に識別するカラム(例:ID経費明細)。
→TBLの中で同じコードが一つしかないよっていう意味
- 親キー(REF):他のテーブルの主キーを参照するカラム(例:ID経費登録)。
Step4|UX設計(フォームと表示)
次に、AppSheetの「UX」タブからビュー(見た目)を設計していきます。
- 経費明細:経費登録のフォーム内で明細を追加できるよう設定
なんだか似たような画面でいまいちややこしいのがAppsheetの唯一の欠点です。
鉛筆マークから編集画面へ移動
※鉛筆マークが出ない場合は下記Switch to the Improved editor をクリック。
お好みのアイコンに変更しましょう。
Step5|動作確認とテスト登録
作成したアプリをプレビューまたはスマホで開き、テストデータを1件入力してみましょう。
今回は、過去の記事で作成したサンプル画像
を取り込んでみます!
領収書を撮影or領収書データを取り込み(ping・Jpegなどの写真情報に限る)
明細を確認してみましょう。
無事に登録されOCRTEXTも機能していることが確認できます。
- ここでGASが回ると・・・?
勘定科目がGEMINI API により自動生成されます。
GASのスクリプトは下記通り!!
同様のスプレッドシートカラム構成であれば、APIKEYとスプレッドシートIDを打ち換えるだけで使用できます!
/**
* Google Apps Script: 領収書OCRテキストから勘定科目を取得し、
* シートに書き込む自動処理(Generative Language API v1beta + Gemini 1.5 Pro)
*
* モデル呼び出し時の JSON ペイロードには `contents` フィールドを使います :contentReference[oaicite:0]{index=0}。
* レスポンスからは最初の候補の content.parts[0].text を抽出します :contentReference[oaicite:1]{index=1}。
*/
// ——— 定数設定 ———
const GEMINI_API_KEY = 'XXXX'; // ご自身の Gemini API キー
const SPREADSHEET_ID = 'YYYY'; // 対象のスプレッドシート ID
const SHEET_NAME = '経費明細'; // 対象シート名
const ERROR_EMAIL = 'your-email@example.com'; // エラー通知先メールアドレス
// ——— モデル名 & エンドポイント ———
const MODEL_NAME = 'gemini-1.5-pro-002';
const ENDPOINT =
'https://generativelanguage.googleapis.com/v1beta/models/'
+ MODEL_NAME
+ ':generateContent?key='
+ encodeURIComponent(GEMINI_API_KEY);
/**
* メイン関数:
* 2行目以降の未処理行を1行だけ処理し、
* K列に勘定科目、M列に「完了」を書き込む
*/
function processReceiptCategory() {
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
const sheet = ss.getSheetByName(SHEET_NAME);
if (!sheet) {
throw new Error(`シート「${SHEET_NAME}」が見つかりません。`);
}
// データ取得(1行目はヘッダー)
const values = sheet.getDataRange().getValues();
for (let i = 1; i < values.length; i++) {
const ocrText = values[i][11]; // L列 (0-based index 11)
const doneFlag = values[i][12]; // M列 (0-based index 12)
// OCRテキストあり & 未処理 の行を処理
if (ocrText && !doneFlag) {
try {
// プロンプト作成
const prompt = [
'以下は領収書のOCRテキストです(ノイズが含まれています)。',
ocrText,
'',
'この中から、会計処理に必要な情報のみ抽出して、最も適切な「勘定科目」を1つだけ日本語で出力してください。'
].join('\n');
// リクエストペイロード
const payload = JSON.stringify({
contents: [
{ parts: [ { text: prompt } ] }
]
// generation_config などを追加したい場合はここに
});
const options = {
method: 'post',
contentType: 'application/json',
payload,
muteHttpExceptions: true
};
// API 呼び出し
const response = UrlFetchApp.fetch(ENDPOINT, options);
const code = response.getResponseCode();
const body = response.getContentText();
if (code === 200) {
const json = JSON.parse(body);
// 最初の候補のテキストを抽出
const parts = json.candidates[0].content.parts;
const category = parts.map(p => p.text).join('').trim();
// K列(勘定科目)と M列(処理完了フラグ)に書き込み
sheet.getRange(i + 1, 11).setValue(category); // K列 (1-based)
sheet.getRange(i + 1, 13).setValue('完了'); // M列 (1-based)
} else {
throw new Error(`Gemini API Error (${code}): ${body}`);
}
} catch (e) {
// エラー時はログ & メール通知
Logger.log(e);
MailApp.sendEmail({
to: ERROR_EMAIL,
subject: '【GAS エラー通知】領収書処理エラー',
body: e.toString()
});
}
// 1行だけ処理したら必ずループを抜ける
break;
}
}
}
/**
* デバッグ用: 利用可能なモデル一覧を Logger に出力
*/
function listModels() {
const url = 'https://generativelanguage.googleapis.com/v1beta/models'
+ '?key=' + encodeURIComponent(GEMINI_API_KEY);
const res = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
Logger.log(res.getContentText());
}
← 前回:構築手順まとめ①
|
次回:OCR×勘定科目の自動判定(Coming Soon) →
0 件のコメント:
コメントを投稿