freeeの見積書作成業務を自動化しよう
こんにちは。にっしーです。
microCMSでは、BizOpsチームで業務改善/Ops自動化を担当しています。
ある日、セールスチームから「見積書作成の負荷が高まっている」という課題が上がってきました。
これまでは担当者が個別に顧客からの問い合わせに応じて見積書を作成していましたが、依頼数の増加に伴い、対応がしきれなくなってきたのです。
そこで、見積書作成業務の自動化に取り組むことにしました。
本記事では、その自動化の概要とポイントを書いていきます。
🌱 改善前の業務フロー
顧客からの問い合わせを受けて、セールス担当者が内容を確認し、freeeにログインして手作業で見積書を作成していました。その後、他のメンバーにSlackでレビュー依頼を出し、OKが出たら顧客に送付するというフローでした。
見積書作成業務には、細かいチェックポイントが多数あり、ミスを防ぐために高い集中力が求められます。
例えば、以下のような点に注意が必要です。
- 企業名の正確性:お客様の企業名に誤りがないかを確認
- 見積日の正しさ:見積書の日付が正しく設定されているかをチェック
- 有効期限の設定:見積書の有効期限が適切に設定されているかを確認
- 明細金額の計算:見積書の明細に記載された金額の計算が正しいかを検証
- ファイル名のフォーマット:見積書のファイル名が決められたフォーマットに沿っているかを確認
これらの確認作業は、一見すると簡単そうに見えますが、実際には神経を使う作業の連続で、地味ながらも大変な業務となっていました。
🌻 改善後の業務フロー
見積書作成フォームへの入力をもとに自動で見積書を作成し、Slack通知するようにしました。
担当者はできあがった見積書を確認し、(必要に応じて編集し、)顧客に送付するフローになりました。
freeeさんが提供している請求書APIで見積書を作成しています。
いろんなAPIを提供&メンテしてくださっているfreeeさんに大感謝です 🙏
なお、GASとfreeeの連携については、アプリケーション登録等の作業が必要です。
公式による丁寧な記事があるのでぜひ参考にしてください。
【freee API】GASを用いてGoogleスプレッドシートと連携する
💬 現場の声
セールス担当者にいただいたフィードバックを一部紹介します。(原文ママ)
🐶「見積もり作成の工数が半分程度になりました!特に従量課金があるパターンの際に、見込みの利用数に合わせて、従量単価を調整する作業がミスしやすい要素となっていたため、こちらが改善されて嬉しいです!」
🐱「記載内容の詳細確認やレビュー依頼など地味ながら大変だった作業の大半がなくなりとても助かりました!更に自動化されることによってミスの割合が大幅に減ったこともすごいことだと思います。」
💡 工夫したポイント
1. シートの設計
GASでシートを処理していく上で、「どのように新着を検知するか」って実は結構面倒なんですよね。
こういったGASの自動化においては、シート設計(=DB設計)が肝だと考えています。(N回目)
今回は次の構成にしました。
- iPaaS経由で「new」シートにデータが追加される
- 「new」シートにデータがあればGASで処理を開始する
- 処理が完了したら内容を「completed」シートに転記する
- 「new」シートの対象行をクリアする
以下に処理を抜粋します。
const createQuotationAndPostToSlack = () => {
const s = SpreadsheetApp.getActive()
const newSheet = s.getSheetByName('new')
const lastRow = newSheet.getLastRow();
const lastColumn = newSheet.getLastColumn();
if (lastRow === 1) {
Logger.log('新規データがないので終了します')
return
}
const range = newSheet.getRange(1, 1, lastRow, lastColumn);
const values = range.getValues();
// 1行目はヘッダ行
const header = values.shift()
values.forEach((row, index) => {
const data = {}
row.forEach((col, index) => {
const key = header[index]
data[key] = col
})
// 取引先検索、作成、見積書作成の処理(中略)
// newシートから行クリア(rowは1始まり + ヘッダ分)
newSheet.getRange(index + 1 + 1, 1, 1, newSheet.getMaxColumns()).clearContent()
// completedシートに転記
const completedSheet = s.getSheetByName('completed')
completedSheet.appendRow(row)
// 以降、Slack通知等の処理
})
}
2. freeeでの取引先検索
見積書の企業名をfreeeの取引先APIで検索するのですが、キーワード検索による部分一致もヒットするので、ちゃんと完全一致で確認するようにしています。
(e.g. 「株式会社micro」で「株式会社microCMS」もヒットしてしまう)
const findPartner = (partnerName) => {
const json = callFreeeApiGetPartners(partnerName)
// キーワード検索だと完全一致ではないので文字列でちゃんと一致を見る
const partner = json.partners.find(p => p.name === partnerName)
return partner ? partner : null
}
const callFreeeApiGetPartners = (keyword) => {
const freeeApp = getService();
const accessToken = freeeApp.getAccessToken();
const requestUrl = `https://api.freee.co.jp/api/1/partners?company_id=${COMPANY_ID}&keyword=${encodeURIComponent(keyword)}`;
const headers = {
"Authorization": "Bearer " + accessToken,
"X-Api-Version": '2020-06-15',
"Content-Type": "application/json"
};
const options = {
method: "get",
headers: headers
};
const res = UrlFetchApp.fetch(requestUrl, options)
const content = res.getContentText();
const json = JSON.parse(content);
return json
}
3. 備考欄のお知らせ
備考欄に入力があれば、 ⚠️で注意喚起してくれます
🍵 おわりに
見積書作成業務の自動化に取り組んだ結果、以下のような効果がありました。
- 作業時間の大幅な短縮
- 人的ミスの防止と正確性の向上
- 業務プロセスの標準化と属人化の解消
もしこの記事が参考になったら、いいねしていただけるととても嬉しいです。
また、記事内で気になる点や追加の質問があればX(旧Twitter)で気軽にメッセージください。
それでは 👋
Discussion