DX

Zoho Inventory の出荷と棚卸差異を freee会計の伝票にする関数を検証【売上原価・棚卸減耗損】

公式コネクタの無いZoho Inventoryとfreee会計をZohoの標準機能とfreee APIでつなぎ、出荷の売上・売上原価と棚卸減耗損の伝票が立つかを検証環境で確かめた記録です。前提になる売上原価対立法と本番の構成も書きました。

Zoho Inventory の出荷と棚卸差異を freee会計の伝票にする関数を検証【売上原価・棚卸減耗損】

公式コネクタの無いZoho Inventoryとfreee会計をZohoの標準機能とfreee APIでつなぎ、出荷の売上・売上原価と棚卸減耗損の伝票が立つかを検証環境で確かめた記録です。前提になる売上原価対立法と本番の構成も書きました。

※ Zoho および Zoho の各製品名・ロゴは Zoho Corporation Private Limited およびその関連会社の商標または登録商標です。freee は freee株式会社の商標または登録商標です。

物販・製造の中小企業では、在庫の数量を Zoho Inventory(在庫・受発注)で、お金を freee会計で管理する組み合わせをよく見かけます。ところが両者をつなぐ公式コネクタは無く、出荷や棚卸のたびに経理が freee 側で仕訳を手で起こすことになりがちです。この記事では、在庫の動きから会計仕訳までを、別のサーバを用意せずに、Zoho の標準機能(ワークフロー、Zoho のスクリプト言語 Deluge で書く関数、出来事を外部へ知らせる Webhook)と freee API(外部のプログラムから freee を操作する窓口)だけで自動化できるかを、Zoho と freee の検証環境で確かめました。本番環境での導入実績ではありません。扱うのは、出荷(→ 売上+売上原価)と棚卸差異(→ 棚卸減耗損)という在庫の2つの動きです。どちらも、関数を手動で実行し、freee に伝票ができるところまで確認しました。棚卸差異は、在庫調整の確定をきっかけにワークフローから関数が自動で呼ばれ、freee に伝票ができるところまで確認しました。出荷の確定から関数を自動で呼び出す部分は設定の手順を示すにとどめ、まだ確かめていません。

この記事でわかること

主な内容は次のとおりです。

  • Zoho Inventory の出荷の内容をもとに、freee会計へ「売上」と「売上原価」(英語で COGS。売れた商品の仕入原価)の伝票を関数で起票する方法
  • 実地棚卸の数量差異(棚卸減耗)について、freee会計へ棚卸減耗損の振替伝票を関数で起票する方法
  • 在庫調整の確定(調整済みへの変換)をきっかけに、ワークフローから関数を自動で呼び出す設定の手順(自動で呼ばれて freee に伝票ができるところまで確認済み)
  • 出荷ごとに原価を振り替えるときの会計の前提(売上原価対立法)と、freee で使う勘定科目
  • 検証で試した2つの認証方式と、本番で勧める Connection 方式(外部サービスの認証情報を設定側に預け、コードからは名前で呼び出す仕組み。トークンをコードに書かずに済む。Salesforce の認証情報の管理機能 Named Credential に相当)
  • Zoho 標準の発注書から始まる仕入の流れと、freee の入金消込の状況を、在庫システムの画面で確かめられるようにする考え方

本記事の内容は Zoho One で試せます。Zoho パートナーである当社経由で無料トライアルを始められます。Zoho One を試す / Zoho CRM / Zoho CRM Plus。なお、Zoho Inventory を使いたい場合は、Zoho One の管理画面から Zoho Inventory アプリを追加(インストール) してください。導入や連携のご相談も受け付けています。

本記事のコンセプト

項目内容
対象読者Zoho Inventory を使う物販・製造の中小企業、freee で会計している経理・情シス
前提知識Zoho の基本操作、freee の管理者アカウント、簿記の基礎(売上原価・棚卸資産)
構築方法CRM の関数(売上+売上原価)と Inventory のワークフロー用の関数(棚卸減耗損)から freee API を呼び、伝票を作る。freee の認証は検証で2つの方式(設定レコード方式と Connection)を試し、本番では Connection を勧める。
環境Zoho One(Inventory 同梱、CRM は Enterprise 相当)と freee会計。どちらも検証環境。
検証の範囲検証環境での動作確認。Zoho Inventory と freee の連携を本番環境に導入した実績はまだ無い。画面に出てくる取引先と商品の名前はすべて架空。

カスタム関数(Deluge)・カスタムボタン・Connection は、Zoho CRM の Enterprise / Ultimate(Zoho One を含む)で利用できます。Zoho Inventory 側で Webhook とカスタム関数を使えるのは Premium と Enterprise プランです。Zoho One には Zoho Inventory も含まれます。出典は Zoho CRM のエディション比較ページと Zoho Inventory のプラン比較ページです。

在庫と会計が分かれていることで起きる課題

Zoho Inventory と freee会計を併用する現場でよく聞く課題は、次の3つです。どれも、在庫は動いているのに、その金額が会計に反映されないことから起きています。

売上原価が月末まで見えない

freee会計の既定の勘定科目は三分法を前提にしており、期中は仕入高で計上し、期末の棚卸で売上原価を確定させる運用が一般的です。そのため期中は、「今いくら売って、原価はいくらで、粗利はいくらか」をその都度確かめられません。在庫システムには数量があるのに、会計には原価が載らないのです。

棚卸差異による損失が会計に反映されない

在庫は「売れて減る」だけではありません。破損・紛失・数え間違い・盗難などで、帳簿在庫と実際の在庫がずれることがあります。これを実地棚卸で発見したときの差が「棚卸差異」で、数量が足りない側(帳簿>実在庫)は「棚卸減耗損」として費用計上します。ところが Zoho Inventory 側で在庫数を実在庫に合わせても、freee 側には「損失が出た」という仕訳が自動では立ちません。

在庫管理のサービスと会計ソフトの二重管理

Zoho Inventory が公式に連携できる会計ソフトは Zoho Books・QuickBooks Online・Xero などの海外製品で、freee やマネーフォワードなど日本の会計ソフトとの公式連携はありません(出典は Zoho Inventory の会計連携ヘルプとプラン比較ページ)。freee も2026年4月に在庫管理のサービス(freee在庫管理)を始めましたが、在庫の管理を Zoho Inventory で続ける会社には、Zoho 側の在庫の動きを freee会計へ渡す仕組みが別に要ります。結果として、出荷や棚卸のたびに経理が freee 側で仕訳を手で起こすことになります。「(借)売上原価 /(貸)商品」や「(借)棚卸減耗損 /(貸)商品」を1件ずつ手で入力するのは手間がかかりすぎるため、多くの現場は期末にまとめて調整しています。その運用では、粗利や損失が数字に現れるのが遅れます。freee会計をこれから入れる段階であれば、導入の順番とつまずきやすい点を整理したfreee 導入の進め方の記事も参考になります。

そもそも Zoho Inventory は在庫管理として何ができるのか

本題に入る前に、連携相手である Zoho Inventory(Zoho One 同梱の在庫・受発注アプリ)が在庫管理として何ができるのかを押さえておきます。商品の登録に加えて、在庫の増減から受発注までを一通り管理できます。

  • 手持ち在庫・引当済み・入荷予定を、商品ごと・倉庫ごとに、その時点の数で追跡
  • 複数の倉庫や保管場所ごとの在庫管理
  • 在庫の調整(棚卸差異・破損・紛失などの増減)と、実地棚卸・循環棚卸(サイクルカウント。毎月一部の商品だけを数える運用)の運用
  • 在庫評価(先入れ先出し法か加重平均法を商品ごとに選択)
  • 受注→出荷までの販売の流れと、発注書→入荷→受取請求書→支払いまでの仕入の流れ
  • 在庫・売上・購入の各種レポート

Zoho Inventory 単体でも、在庫の数量はかなり正確に追えます。足りないのは、その動きが会計の金額に自動では反映されない点で、ここはシステム連携で補えます。在庫が動いたらその金額を freee に仕訳する、という考え方を、この記事では2つの関数で試します。

日本で Zoho Inventory を使うときに標準機能だけでは足りない領域

Zoho Inventory は日本語の画面・日本のデータセンター・日本円に対応し、在庫の数量管理としては日本でも問題なく使えます。ただし「日本の商習慣・税制・国内サービス」の面では、標準機能だけだと噛み合わない箇所があります。主な領域は次の表のとおりです(言語や契約可否の問題ではありません)。

領域Zoho 標準の対応日本で不足する点
会計・税制連携先は Zoho Books・QuickBooks Online・Xero など海外製品Zoho Japan がインボイス制度対応として案内しているのは Zoho CRM と Zoho Invoice(2023年5月時点の案内、出典は Zoho Japan のインボイス制度対応ページ)。Zoho Books を日本の消費税・インボイスに使えるかは導入前に確かめる必要がある。
会計ソフト連携Zoho Booksfreee・マネーフォワード等の国内会計ソフトに公式連携が無い
EC・モールAmazon・eBay・Shopify 等楽天市場・Yahoo!ショッピングに非対応
決済PayPal・Stripe 等の海外系国内決済ゲートウェイに非対応
配送UPS・FedEx・Easyship など海外系ヤマト運輸・佐川急便・日本郵便に標準では非対応

裏を返せば、どれも Zoho だけで完結させようとした場合に足りない部分です。各領域を日本向けのサービスと API で連携すれば補えます。この記事の主題である会計連携(freee)は、その最初の例です。

会計・配送・EC を API 連携で補う

どの領域も、この記事と同じ組み方で補えます。在庫と業務の記録は Zoho の内容を基準にし、専門の機能は日本向けのサービスに任せます。両者は Connection とカスタム関数(または Webhook)でつなぎます。

領域つなぎ先(日本特化)つなぎ方
会計freee会計(本記事)カスタム関数と Connection で freee の取引(API 名 deals)と振替伝票(API 名 manual_journals)を起票
配送Ship&co 等の送り状発行API(ヤマト・佐川・日本郵便対応)出荷の確定をきっかけに送り状を発行し、追跡番号を Zoho に書き戻す
EC・モール楽天RMS・Yahoo!・Amazon SP-API、または多店舗一元管理ツール受注の取込と在庫の同期。売り越しを防ぐ同期の設計が要る

各モールの API には契約・審査・呼び出し回数の上限があり、楽天はライセンスキーが3か月で失効します(更新は手動)。送り状の API は従量課金です。会計から始め、配送や EC は必要になった時点で同じ組み方で足していくのが現実的です。

在庫の動きと会計仕訳の対応

在庫の動きは、入る(仕入・入荷)、出る(販売・出荷)、ズレる(棚卸差異)の3つに分けられます。どれも在庫の増減であり、同時に会計上の仕訳が発生する出来事でもあります。多くの現場では、在庫システムの動きと会計の仕訳を人が別々に扱い、月末にまとめて突き合わせています。在庫が動いた時点で対応する仕訳を自動で立てられれば、この突き合わせの手間が減ります。

在庫の動き ↔ 会計仕訳の対応表

在庫の動き会計上の仕訳(例)きっかけ本記事での扱い
入る(仕入・入荷)(借)商品 (貸)買掛金発注書の入荷発展(後述)
出る(販売・出荷)売上 + 売上原価出荷の確定①
ズレる(棚卸減耗)棚卸減耗損在庫調整の確定(調整済みへの変換)②

この記事では、在庫が減る2大要因である「出る(①)」と「ズレる(②)」を freee に仕訳する仕組みを作ります。残る「入る」を足せば、在庫のすべての動きが会計に反映されます。先に、① と ② に共通する役割分担と認証の方式を説明します。

① と ② に共通する役割分担と認証の方式

①(出荷)も ②(棚卸差異)も、役割分担は同じです。数量は Zoho(在庫システム)、金額は freee(会計)、認証は Connection(Zoho 側で認証情報を預かる機能)が受け持ちます。とくに認証の置き方は、本番で使えるかどうかを左右します。freee のアクセストークン(API を呼ぶときに示す、有効期限つきの鍵)を Webhook の通信に付ける情報(ヘッダ)やコードに直接書くと、編集権限を持つ人にトークンの文字列がそのまま見えます。しかも6時間で失効し、自動では更新できません。アクセストークンを埋め込む構成は、本番では使えません。

本記事の検証では、freee の認証を2つの方式で試しました。1つ目は、Zoho CRM 内の設定レコードに freee の接続情報を置く方式です(以下、レコード方式)。関数は更新トークン(refresh_token。アクセストークンを取り直すための、有効期間の長いトークン)でアクセストークンを取り直し、新しい更新トークンを設定レコードに保存し直します。2つ目が Connection です。レコード方式でも動きますが、トークンの保存と更新を自分のコードで管理することになるので、本番では Connection を勧めます。

認証情報はコードに書かず、Connection に預けます。Zoho の Connection は Salesforce の Named Credential に近い仕組みです。OAuth トークン(freee に接続するための鍵一式)を Zoho 側で保管し、期限が切れたアクセストークンを自動で取り直します(freee のアクセストークンは6時間で失効します)。開発者はコードから connection:"freee_conn" と参照するだけで、Authorization ヘッダもトークン文字列も書きません。CRM を Salesforce で運用している場合の freee 連携は、Salesforce と freee の連携で経理・営業データを自動化した記事で紹介しています。

もう一つの共通点は会計設計の前提です。freee の既定の勘定科目は三分法(仕入を「仕入高」で受け、期末に「期首商品棚卸高+当期仕入高−期末商品棚卸高」で売上原価を出す方法)に沿っていて、「売上原価」も「商品の棚卸減耗損」も単独の勘定科目としては用意されていません。

出荷のたびに原価を振り替える方式は、売上原価対立法(仕入を「商品」勘定で受け、商品を払い出すたびに商品から売上原価へ振り替える方法)が前提です。売上原価対立法は、継続記録法で払出数量を記録していることを前提にしています。仕入を「仕入高」で受ける三分法のまま運用すると、出荷ごとの振替で計上した原価と、期末に「期首+仕入−期末」で計算した原価が二重に計上されます。商品勘定も、仕入で増えないまま払出だけが引かれるので、期首残高を超えて払い出すとマイナスになります。この連携を入れるときは、仕入の受け方を売上原価対立法に切り替えます。

本番で勧めるのは、freee の勘定科目に「売上原価」を売上原価の区分で追加し、出荷ごとに (借)売上原価 /(貸)商品 で起票する形です。本記事の検証では勘定を追加せず、freee の既定の科目で代用して (借)期末商品棚卸高 /(貸)商品 で起票しました。この代用だと、期中の試算表では期末商品棚卸高がマイナスで表示されます。

売上原価対立法への切り替え、勘定科目の追加、棚卸減耗損の区分、評価方法(移動平均・総平均など)は会計方針の判断です。はてなベースでは、公認会計士・税理士法人が連携を組む前の会計設計から加わります。

① 出荷 → 売上+売上原価(COGS)

まずは「出る(販売・出荷)」です。Zoho Inventory で商品を出荷したときに、freee会計へ売上取引と売上原価の振替伝票を起票します。検証では、受注書 SO-00001(サンプル商品A 2個×5,000円)の内容を引数に、関数を手動で実行しました。受注の時点で売上を立てると出荷基準より早くなるため、本番では出荷(発送済み)の確定を処理のきっかけにします。処理の中心は Zoho CRM のコネクタ関数(CRM から外部サービスを呼ぶために置く関数)postSalesToFreee で、freee の認証には前の節のレコード方式を使います。検証環境で手動実行したときの返り値は次のとおりです(取引と振替伝票の ID は伏せています)。

jsonpostSalesToFreee の返り値(検証環境、ID は伏せ字)
{"deal_id":"<取引ID>","manual_journal_id":"<振替伝票ID>","sales":10000,"cost":6000}
Zoho CRM のコネクタ関数 postSalesToFreee を検証環境で手動実行した画面。ステータスは成功で、売上取引と振替伝票の ID が返っている。設定レコードの ID とキー名、トークンの取得先、返ってきた ID、勘定科目 ID と税区分の値は塗りつぶしている
コネクタ関数 postSalesToFreee を手動で実行した結果。freee に売上取引と売上原価の振替伝票が起票され、それぞれの ID が返った(一部を塗りつぶし)。検証時のコードは税区分に 21(課税売上)を指定していた。10%の課税売上は 129

これで freee の検証環境に、10,000円の売上取引と、売上原価6,000円の振替伝票が起票されました。条件は、サンプル商品A を2個、売価5,000円、原価3,000円です。freee の取引 API は明細の金額を税込で受け取る仕様なので、売上は税込10,000円で送りました。税抜経理の事業所では売上高9,091円と仮受消費税909円に分かれ、粗利は3,091円です。売価を税抜5,000円として扱うなら、取引には税込11,000円で送ります。

検証で freee に起票された内容

項目金額freee 側
売上(税込)¥10,000取引。税抜経理では売上高¥9,091と仮受消費税¥909に分かれる
売上原価¥6,000振替伝票
粗利(税抜経理の場合)¥3,091税抜の売上高と売上原価の差額

表の上の2行は、別々の API で起票しています。売上は取引として、売上原価は振替伝票として立てるため、freee の画面でも取引一覧と振替伝票一覧に分かれて表示されます。どの勘定を使うかは次の節で説明します。

検証で使った勘定と本番で使う勘定

検証では「売上原価」勘定を追加せず、freee の既定の科目で代用しました。起票したのは次の2本です。本番で勧める形との違いは、売上原価の振替伝票の借方の科目だけです。表とコードの税区分は本番で使う値で、検証で売上を起票したときは税区分 21(課税売上)を指定していました。

起票する2本の仕訳

区分API仕訳税区分
売上POST /api/1/deals(type=income)(借)売掛金 /(貸)売上高。金額は税込で指定する129(課税売上10%)
売上原価POST /api/1/manual_journals(振替伝票)検証は (借)期末商品棚卸高 /(貸)商品〈棚卸資産〉。本番は (借)売上原価 /(貸)商品。金額は数量×原価2(対象外)

期末商品棚卸高を借方に置いても、損益計算書では売上原価が増え、貸借対照表では商品が減ります。ただし期中の試算表では期末商品棚卸高がマイナスで表示され、試算表を見る人が戸惑います。本番では「売上原価」勘定を追加して使います。

Inventory の有効化と原価付き商品の準備

Zoho One に Zoho Inventory を追加し(同梱・追加費用なし)、クイックセットアップ(通貨 JPY・会計年度)を行うと、「はじめに」の画面が開き、商品・在庫・売上・購入のメニューが使えるようになります。次に「商品 > 新しい商品」で、販売価格(5,000)と原価(3,000)を持つ商品を作成します。原価は、売上原価の金額を出すのに使います。「単位」と「在庫の勘定」を設定しないと、商品を保存できません。

Inventory ダッシュボード
商品・在庫・売上・購入のタブが並ぶダッシュボード
Zoho Inventory の新しい商品フォームの購入商品欄。原価3,000、勘定は売上原価
商品フォームの購入商品欄。原価3,000と、仕入側の勘定(売上原価)を設定

CRM のコネクタ関数 postSalesToFreee の実装

「設定 > 開発者向け情報 > 関数」でコネクタ関数を作成します。この関数は、設定レコードから接続情報を読み、更新トークンでアクセストークンを取り直します。新しい更新トークンを設定レコードに保存し、読み直して保存できたことを確かめてから、取引と振替伝票を起票します。本番で使う場合は、このトークン管理を Connection に置き換えます(次の節)。

javascriptpostSalesToFreee.dg(主要ロジック抜粋)
string standalone.postSalesToFreee(String partnerId, String salesAmount, String costAmount, String memoText)
{
    CONFIG_ID = <設定レコードのID>;
    ACC_SALES = <売上高の勘定科目ID>;
    ACC_COGS_DEBIT = <期末商品棚卸高の勘定科目ID>;   // 借方
    ACC_INVENTORY = <商品の勘定科目ID>;            // 棚卸資産・貸方
    // ... freee token 更新(refresh_token で取り直し → 新しい refresh_token を設定レコードへ保存し読み直して確認)...

    // 売上 deal
    dealDetail = Map();
    dealDetail.put("account_item_id", ACC_SALES);
    dealDetail.put("tax_code", 129);  // 課税売上10%
    dealDetail.put("amount", salesAmount.toLong());  // 税込で指定
    dealPayload = Map();
    dealPayload.put("company_id", company_id.toLong());
    dealPayload.put("issue_date", today);
    dealPayload.put("type", "income");
    dealPayload.put("partner_id", partnerId.toLong());
    dealPayload.put("details", {dealDetail});
    // POST https://api.freee.co.jp/api/1/deals  (parameters: dealPayload.toString())

    // 売上原価 manual_journal(借 期末商品棚卸高 / 貸 商品)
    dr = Map(); dr.put("entry_side","debit");  dr.put("account_item_id",ACC_COGS_DEBIT); dr.put("tax_code",2); dr.put("amount",costAmount.toLong());
    cr = Map(); cr.put("entry_side","credit"); cr.put("account_item_id",ACC_INVENTORY);  cr.put("tax_code",2); cr.put("amount",costAmount.toLong());
    mjPayload = Map();
    mjPayload.put("company_id", company_id.toLong());
    mjPayload.put("issue_date", today);
    mjPayload.put("details", {dr, cr});
    // POST https://api.freee.co.jp/api/1/manual_journals  (parameters: mjPayload.toString())

    return "{\"deal_id\":\"...\",\"manual_journal_id\":\"...\"}";
}

ポイント解説

実装では次の2点に気をつけます。

  • freee 呼び出しの parameters は payload.toString()(JSON文字列)で渡す。Map をそのまま渡すとフォーム形式(form-urlencoded)に変換され、Content-Type の指定が無視される。
  • updateRecord の第4引数に {"trigger":[]} を渡し、設定レコードの更新で自動処理が動かないようにする(関数の呼び出しが際限なく繰り返されるのを防ぐ)

本番で勧める Connection 方式での起票

本番で勧めるのは、トークンを Connection に預ける形です。関数は出荷の金額と明細を受け取り、connection:"freee_conn" を指定して freee の取引と振替伝票を起票する作りにします。レコード方式との違いは、コードにトークンが一切出てこないことです。トークンの保存や更新も書かずに済むので、関数には起票の処理だけが残ります。

javascriptConnection 経由の freee 呼び出し(トークン非埋め込み)
// トークンをコードに一切書かない。Authorization ヘッダも無い。
resp = invokeurl
[
    url: "https://api.freee.co.jp/api/1/deals"
    type: POST
    parameters: dealPayload.toString()
    headers: {"Content-Type":"application/json"}   // ← Authorization は書かない
    connection: "freee_conn"                         // ← トークンは Zoho が自動注入
    detailed: true
];

検証環境では、トークンを埋め込まないこの関数を手動で実行し、freee に売上取引(税込¥10,000)が1件起票されることを確認しました。この方式での振替伝票の起票は、まだ試していません。Connection はアクセストークンの取得と期限切れ時の取り直しを受け持つので、トークンをコードに書かずに済みます。ただし90日を超える運用は、まだ確かめていません。

出荷の確定から関数を自動で呼ぶ設定

自動で呼び出す設定は、本番で Connection 方式の関数に対して行います。postSalesToFreee は Zoho CRM 側の関数なので、Zoho Inventory のワークフローから直接は呼べません。そこで、Zoho Inventory 側にも同じ処理の関数を作り、Connection(freee_conn)も Inventory 側に作ります。そのうえで Inventory のワークフロールールに、出荷(発送済み)が確定したときにこの関数を実行するよう設定します(条件に使う項目名は、Zoho Inventory のワークフロー設定画面で確かめてください)。② の関数と同じ置き方です。Webhook で freee を呼ぶ構成にする場合も、Zoho Inventory の Webhook 設定で認証に Connection を選べるので、トークンをヘッダに書く必要はありません(出典は Zoho Inventory の Webhook 作成ヘルプ)。出荷の確定から Connection 方式の関数を自動で呼んだときに freee に伝票ができるかは、本記事ではまだ確かめていません。自動で呼ぶ仕組みそのものは、別の試験用の構成で確かめています。受注書を作ったときに Webhook で freee を呼ぶ構成で、受注書を1件作ると、freee に10,000円の売上の取引が自動でできました。ただしこの構成は、トークンを Webhook のヘッダに直接書いた、原理を確かめるためのものです。本番には使えず、売上を立てる時点も出荷ではなく受注のときになっています。本番で使う前に、テスト用の出荷を1件確定し、freee の取引一覧と振替伝票一覧に1件ずつ増えることを確かめてください。

Zoho Inventory の受注書 SO-00001(合計10,000円)。取引先名は塗りつぶしている
検証で関数の引数に使った受注書 SO-00001(合計10,000円。取引先名は塗りつぶし)

② 棚卸差異 → 棚卸減耗損

次は「ズレる(棚卸差異)」です。具体例で進めます。サンプル商品A(原価3,000円)の帳簿在庫は480個でしたが、実地棚卸で数えると475個しかありませんでした。5個の減耗です。この5個ぶんの原価 5×3,000=15,000円 を、棚卸減耗損として freee に計上します。Zoho Inventory では「在庫の調整」で数量を実在庫(475個)に合わせ、その調整を確定(調整済みに変換)したときに freee へ仕訳を起票します。

Zoho Inventory の在庫の調整フォーム。サンプル商品A の在庫量480個・新しい数量475・調整数量マイナス5、詳細に「実地棚卸との差異(棚卸減耗)帳簿480個→実地475個=5個不足」と入力されている
Zoho Inventory の「在庫の調整」画面。帳簿480個を実地の475個に合わせ、調整数量 −5(=5個の減耗)を入力。この調整を確定すると、freee へ棚卸減耗損を起票する。

在庫の調整には数量と金額の2種類がある

棚卸差異を会計へ渡す起点は「在庫の調整(Inventory Adjustment)」です。調整の方法は次の2つから選びます。

調整方法何を調整するか使う場面
数量の調整数量を増減する(新しい数量 または ±調整数量を入力)棚卸差異・破損・紛失など(本記事)
調整の合計値在庫の評価額(金額)を調整する時価下落による評価替え・商品評価損

この記事で使うのは「数量の調整」です。在庫量480に対して新しい数量475を入れると、調整数量は自動で −5 と計算されます。時価が下がったときの「商品評価損」は、金額を調整する「調整の合計値」の側で扱います。Zoho Inventory の在庫評価は、先入れ先出し法(FIFO)と加重平均法から選べます。この検証の商品は先入れ先出し法なので、厳密には減耗した5個がどの仕入分に当たるかで単価が変わります。本記事はデモとして原価3,000円で単純化しています。

見落としやすいのは保存の種類です。「下書きとして保存する」では在庫は変わらず、「調整済みに変換」を押して初めて手持ち在庫が減ります。関数を自動で呼ぶきっかけも、調整が「調整済み」になった時点(在庫に反映された時点)に合わせます。下書きの段階で仕訳を立てると、在庫は減っていないのに freee に損失が載ってしまいます。

freee の既定の勘定科目に「商品の棚卸減耗損」が無い

freee の既定の勘定科目一覧(三分法)を実際に確認したところ、「商品用の棚卸減耗損」勘定はありませんでした。減耗損は [製]棚卸減耗損(製造原価報告書向け)しかなく、商品(小売・卸)を扱う会社には合いません。そこで、既存の勘定で棚卸減耗損を表現します。

起票する仕訳(本記事の検証)

借方貸方税区分金額
雑損失商品〈棚卸資産〉対象外(2)不足数量 × 原価 = 5 × 3,000 = 15,000

本記事の検証では、簡便のため借方を「雑損失」にして起票しました。ただし雑損失は営業外費用なので、ここに載せてよいのは異常な減耗に限られます。本番では、減耗の性質に応じて次のように分けます。

  1. 正常な範囲の減耗は、freee に「棚卸減耗損」勘定を売上原価の区分か販売費及び一般管理費の区分に追加し、(借)棚卸減耗損 /(貸)商品 で計上する
  2. 災害や盗難など通常の営業では起きない異常な減耗は、雑損失などの営業外費用か特別損失で計上する
  3. 三分法のまま期末の実地棚卸で期末商品棚卸高を確定させると、期中に振り替えた減耗分が期末の計算でも原価に入り、二重に計上される。① と同じく、売上原価対立法が前提になる

棚卸減耗損は、原価性がある(正常な範囲の)減耗なら売上原価か販売費及び一般管理費に、原価性がない(異常な)減耗なら営業外費用か特別損失に表示します。どちらに当たるかは減耗の原因と頻度から判断するもので、関数の側では決められません。自動化で受け持てるのは、判断が済んだ仕訳を在庫調整の確定に合わせて立てるところまでです。

減耗数量×原価を1本の振替伝票にする実装

② の関数は、最初から Connection(freee_conn)で freee を呼ぶ形で作りました。Zoho Inventory 側にも、① と同じ設定の Connection(freee_conn)を作成して使います。② で新しいのは freee 側の中身です。売上は取引(deal)として起票しましたが、減耗損は減耗数量×原価を1本の振替伝票(manual_journal)にして起票します。関数の中心部分は次のとおりです。

javascriptpostShrinkageToFreee.dg(中核)
// 減耗損の金額 = 不足数量 × 原価単価
lossAmount = shortageQty.toLong() * unitCost.toLong();

// (借)雑損失 /(貸)商品, 対象外
dr = Map(); dr.put("entry_side","debit");  dr.put("account_item_id", <雑損失の勘定科目ID>); dr.put("tax_code",2); dr.put("amount",lossAmount);
cr = Map(); cr.put("entry_side","credit"); cr.put("account_item_id", <商品の勘定科目ID>); cr.put("tax_code",2); cr.put("amount",lossAmount);

mj = Map();
mj.put("company_id", <事業所ID>);
mj.put("issue_date", zoho.currentdate.toString("yyyy-MM-dd"));
mj.put("details", {dr, cr});

resp = invokeurl
[
    url: "https://api.freee.co.jp/api/1/manual_journals"
    type: POST
    parameters: mj.toString()
    headers: {"Content-Type":"application/json"}
    connection: "freee_conn"   // ← トークンはConnectionが自動注入(① 参照)
    detailed: true
];

検証環境では、この関数を手動で実行し、freee に棚卸減耗損の振替伝票((借)雑損失15,000 /(貸)商品15,000、2026-07-21付)が起票されることを確認しました。トークンはコードに書かず、Connection に預けています。

freee会計の振替伝票一覧。2026-07-21 に借方=雑損失15,000/貸方=商品15,000 の棚卸減耗損の伝票が起票されている。下段は2026-07-19の売上原価(期末商品棚卸高6,000/商品6,000)
freee の検証環境の振替伝票一覧。最上段が棚卸減耗損(雑損失15,000/商品15,000)で、その下は ① の売上原価。07-19 付の期末商品棚卸高の行が複数あるのは、検証で関数を複数回実行したため。

在庫調整の確定から関数を自動で呼ぶ設定

① は出荷の確定、② は在庫調整の確定が呼び出しのきっかけです。関数を自動で呼ぶには、Zoho Inventory でワークフロールール(この記事では「棚卸減耗損を自動計上」と名付けました)を作り、処理に先ほどの関数を設定します。呼び出すきっかけは、在庫調整が「調整済み」になった時点(在庫に反映された時点)に合わせ、下書きのまま保存した調整では関数が動かないようにします。条件に使う項目名は、Zoho Inventory のワークフロー設定画面で確かめてください。

ワークフローに関連付けた関数は、関数名と引数の形(署名)を Inventory が自動で作ります。手動テスト用の postShrinkageToFreee(String shortageQty, String unitCost) とは違い、ワークフローから呼ばれる版は void postshrinkagetofreee(Map inventory_adjustment, Map organization, Map user) という形です。呼び出しのきっかけになった在庫調整そのものが inventory_adjustment として渡ってきます。そのため関数の中で、渡された在庫調整の明細を読んで金額を組み立てます。

本体では、明細(line_items)を1行ずつ見て、quantity_adjusted が負(=不足)の行だけを取り出し、その絶対値を足し合わせて不足数量を求め、原価を掛けて金額にします。これで、どの在庫調整から呼ばれても、その調整の実際の不足数がそのまま freee の減耗損の金額になります。

javascriptワークフロー版 postshrinkagetofreee(本体・動的解析)
// Inventory が署名を自動生成(本体のみ編集)
// void postshrinkagetofreee(Map inventory_adjustment, Map organization, Map user)

// 在庫調整の明細から「不足数量」を動的に読み取る
lineItems = inventory_adjustment.get("line_items");
shortageQty = 0;
for each li in lineItems
{
    qadj = ifnull(li.get("quantity_adjusted"), 0).toDecimal();
    if(qadj < 0)
    {
        shortageQty = shortageQty - qadj;   // マイナス調整の絶対値を積算
    }
}
if(shortageQty <= 0) { return; }            // 増加方向の調整なら何もしない

lossAmount = (shortageQty * 3000).toLong(); // 不足数 × 原価単価(デモは3,000固定)
// 以降は (借)雑損失 /(貸)商品 の manual_journal を connection:"freee_conn" で起票
info resp;                                   // ← freee の生レスポンス(manual_journal ID)をログに残す

在庫調整を確定したときにワークフロー経由で関数が自動で呼ばれ、freee に伝票が立つことも確認しました。検証環境の Zoho Inventory のワークフローのログには、在庫調整をきっかけにした実行が4回記録され、4回とも成功し、freee から伝票の作成完了の応答が返っています(2026年7月)。コードの単価3,000円と、前の関数の事業所IDは、デモ用に固定した値です。本番では、品目に登録された原価を読んで金額を計算します。本番で使う前に、テスト用の在庫調整を1件確定し、freee の振替伝票一覧に伝票が増えることを確かめてください。あわせて、Zoho Inventory の「ワークフローのログ」に関数の実行結果と freee の返り値が残っているかも見ておきます。

確かめるときは、ログに残る内容も決めておくと後で困りません。上のコードの最後にある info resp; は、freee が返した内容(振替伝票の ID など)をワークフローのログに書き出す行です。伝票が増えていないときも、このログを見れば freee がエラーを返したのか、関数が呼ばれていないのかを切り分けられます。

なぜ在庫が動いた時点で仕訳を立てるのか

同じ仕訳でも、いつ起票するかで実務での使い道が変わります。期末に棚卸減耗や売上原価をまとめて調整する運用だと、損失や粗利が数字に現れるのは決算のときだけです。「いつ・どの商品で・どれだけ動いたのか」が分からなくなり、破損なのか紛失なのか検品ミスなのか、原因を調べる手がかりも薄れます。在庫が動いた時点で仕訳を起票すれば、期中でも粗利や損失の金額をその都度確かめられます。循環棚卸とはとくに相性がよく、差異が出るたびに会計へ反映されるので、異常に早く気づけます。

役割分担(数量は Zoho、金額は freee、認証は Connection)が決まっているので、新しい在庫の動き(返品、廃棄、評価損、仕入の未払計上など)を足すときも、呼び出すきっかけと勘定科目を変えた同じ作りの関数を1本増やすだけで済みます。在庫システムと会計は別々のシステムのまま、在庫の1つ1つの動きが会計の1仕訳に対応します。この記事でいう「在庫と会計の一体化」は、この状態を指します。

ただし、仕訳を自動で起票する仕組みを入れると、監査では「その仕訳を誰が、何を根拠に起票したか」「誤った仕訳をどう止めるか」を聞かれます。AI エージェントに仕訳を起票させる場合の論点を仕訳の自動起票と監査対応の記事にまとめており、決まったルールで動く本記事の関数にも当てはまる部分があります。

仕入・発注(発注書)も同じ仕組みで freee へ流す(発展編)

残る「入る(仕入・入荷)」側も、同じ組み方で自動化できる見込みです。この節は設計の考え方で、本記事では検証していません。Zoho Inventory にはメニューの「購入 > 発注書」に発注書の機能が標準で入っており、仕入先 → 発注書 → 購入受領(入荷)→ 受取請求書 → 支払い までを続けて管理できます。追加の拡張機能は要りません。

Zoho Inventory の発注書 PO-00001。標準機能で作成した発注書の画面で、仕入先名は塗りつぶしている
発注書 PO-00001(仕入先名は塗りつぶし)を標準機能だけで作成

この発注書の「作成時/入荷時」をきっかけに、本記事と同じワークフロー+関数で freee に「(借)商品 /(貸)買掛金」を計上する作りが考えられます。借方を商品にするのは、① と同じく売上原価対立法を前提にしているためです。そうすれば「発注 → 入荷 → 未払計上 → 支払消込」という仕入サイクルも、Zoho 標準の発注書と freee の取引(type=expense)・振替伝票でつなげられます。

発注書は Zoho と freee のどちらで作るか

「発注書は freee 側でも作れるのでは?」と考える人もいるはずです。実際、freee でも API で発注書を作成・管理できます。どちらで持つかは、freee の API が製品ごとにどう分かれているかを踏まえて決めます。

freee の発注書 API をめぐる状況

freee 側の発注書 API は、対象プロダクトによって扱いが分かれます。

  • freee会計の仕訳を扱う API(/api/1)には発注書そのものは無い(扱えるのは取引 deals・振替伝票 manual_journals などの会計仕訳)
  • freee請求書(/iv API)は見積・発注書・納品・請求・領収を扱え、POST /purchase_orders で発注書を作成し、GET で取得、PUT /purchase_orders/{id}/cancel で取消できる。2026年9月の仕様変更で、発注先の取引先は「仕入先」の設定をオンにしておく必要がある(出典は freee Developers Community のお知らせ)。
  • freee販売(/sm API)にも発注 API がある(2026年6月24日に追加。出典は freee Developers Community のお知らせ)。こちらは販売管理の製品から使う経路。

どちらで発注書を持つかは要件次第ですが、この記事では在庫と発注の元データを Zoho Inventory にまとめる設計を採ります。発注書という業務書類は Zoho Inventory の標準機能で作成・管理し、freee にはその結果の会計仕訳(買掛・未払)だけを API で渡します。在庫システムを唯一の基準にするなら、この分け方が無理がありません。freee請求書や freee販売の API を使い、freee 側で発注書を持つ構成も可能です。

在庫管理と入金消込を一体化する

ここまでで「出荷 → 売上計上」と「棚卸差異 → 減耗損」の仕訳を起票する仕組みを見てきました。もう一歩進めて、入金消込(入金と売上を突き合わせ、未回収の残高を消す作業)まで在庫システムと一体で見えるようにする考え方を示します。この節も設計案で、動作の検証結果ではありません。流れは、出荷に合わせて freee に売上取引を起票し、freee で入金消込を済ませ、その入金状況を Zoho の受注に書き戻す、の3段です。

Zoho の出荷に合わせて起票した freee の売上取引は、当初 payment_status = unsettled(未入金)です。実際に入金があると、freee の入金消込(口座明細と取引の突合)で settled(入金済)になります。この payment_status を freee API(GET /api/1/deals)で読み取り、Zoho 側の受注に「入金済/未入金」として書き戻すことで、受注ごとの入金消込の状況を在庫システムの画面で確かめられます。

在庫の動きは Zoho、入金の消し込みは freee で管理したまま、受注から入金までの進み具合を Zoho の画面で追えるようになります。

Zoho と freee で連携を組むときの注意点

この連携を自分で組むときに、先に知っておくと手戻りを減らせる点を挙げます。会計設計と認証のほか、Deluge の書き方、Inventory の設定、プランにも注意点があります。

  • 会計設計では、出荷ごとの原価振替が売上原価対立法を前提にしている点に注意する。三分法のままだと期末の計算と二重に原価が立つ。本番は「売上原価」と「棚卸減耗損」の勘定を追加して起票し、雑損失は異常な減耗に限る
  • 認証で最も気をつけたいのは、freee の更新トークンが1回使うと無効になり、新しい値に替わることだ(アクセストークンは6時間、更新トークンは90日で失効)。検証ではレコード方式で自前管理も試したが、本番は Connection に預ければトークンの取り直しを Zoho が受け持ち、コードにトークンを書かずに済む(90日を超える運用はまだ確かめていない)
  • 認証でやってはいけないのは、アクセストークンを Webhook ヘッダや設定画面に平文で書くことだ。編集権限を持つ人に見え、失効しても自動で更新できない。本番は connection:"freee_conn" のように Connection を指定し、トークンをコードから外す。OAuth の接続を専用の連携基盤でまとめて管理する方法もあり、連携基盤 Nango をセルフホストして試した記事では、freee の接続設定が用意されていない点も含めて書いている
  • Deluge の invokeurl で parameters に Map をそのまま渡すと、form-urlencoded 形式に変換され Content-Type の指定が無視される。payload.toString() で JSON 文字列にして渡す
  • Inventory の商品フォームは「単位」と「在庫の勘定」が必須で、未設定だと保存できない。在庫調整は「調整済みに変換」で初めて在庫が動くので、関数を自動で呼ぶきっかけもこの確定の時点に合わせる
  • プランの確認も要る。Zoho Inventory で Webhook とカスタム関数を使えるのは Premium と Enterprise プラン、Zoho CRM でカスタム関数・カスタムボタン・Connection を使えるのは Enterprise / Ultimate(Zoho One を含む)だ。出荷や在庫調整から関数を自動で呼ぶなら、関数と Connection を Zoho Inventory 側に置く構成を勧める。CRM 側の関数は Inventory のワークフローから直接は呼べないため、Inventory のプランを先に確かめる

手作業と自動化の違い

検証環境で確かめた範囲と、本番で Connection に切り替えたときの想定を合わせて、手作業との違いを整理します。

手作業と自動化の比較

これまで(手作業)連携後(自動)
売上の会計計上経理が freee で手入力出荷の確定をきっかけに起票(自動の呼び出しは本番前に要確認)
売上原価期末にまとめて調整出荷ごとに振替(売上原価対立法が前提)
棚卸減耗損期末棚卸で一括・期中は見えない在庫調整の確定をきっかけに起票(自動の呼び出しは本番前に要確認)
粗利・損失が分かる時期月末〜決算まで見えない在庫が動いた時点
在庫↔会計二重管理数量=Zoho / 金額=freee で連動

まとめ

この記事のポイント

本記事の要点をまとめます。

  • 公式コネクタの無い Zoho Inventory と freee について、Zoho の関数から freee API を呼んで伝票を起票できることを、検証環境で確かめた(棚卸差異はワークフローからの自動呼び出しまで確認した。出荷の自動呼び出しと本番導入は未確認)
  • ① の出荷では、関数を手動で実行し、freee に売上取引と売上原価の振替伝票が立つことを確認した。出荷の確定から自動で呼ぶ設定は、本番で Connection 方式の関数に対して行う
  • ② の棚卸差異では、Connection を使う関数を手動で実行し、棚卸減耗損の振替伝票の起票を確認した。在庫調整の確定からワークフローで自動で呼び出し、freee に伝票が立つことも確認した
  • 出荷ごとの原価振替は売上原価対立法が前提で、三分法のままだと原価が二重に立つ。本番は「売上原価」「棚卸減耗損」の勘定を追加し、雑損失は異常な減耗に限る
  • 認証は検証でレコード方式と Connection の2つを試した。本番では、トークンを埋め込まずに Connection へ預ける形を勧める
  • 役割分担(数量は Zoho、金額は freee、認証は Connection)が同じなので、発注(入る)・返品・廃棄なども関数を1本ずつ足していける
  • 発注書は Zoho を正として作り、freee には会計仕訳だけを流す。入金消込まで反映すれば、出荷→売上→入金→消込の進み具合を Zoho の画面で追える

本記事の動作確認は、Zoho One と freee の検証環境で行ったもので、本番環境での導入実績ではありません。仕様・料金・エディションは変更される場合があるため、本番導入時は各サービスの最新情報をご確認ください。勘定科目と税区分は、会計方針とあわせて決めてから運用を始めてください。

本記事の内容は Zoho One で試せます。Zoho パートナーである当社経由で無料トライアルを始められます。Zoho One を試す / Zoho CRM / Zoho CRM Plus。なお、Zoho Inventory を使いたい場合は、Zoho One の管理画面から Zoho Inventory アプリを追加(インストール) してください。

※ Zoho、Zoho CRM、Zoho Inventory、Deluge および Zoho の各製品名・ロゴは Zoho Corporation Private Limited およびその関連会社の商標または登録商標です(The Zoho logo is a registered trademark of Zoho Corporation.)。freee は freee株式会社の商標または登録商標です。本記事ははてなベース株式会社が独自に検証・作成したものであり、Zoho Corporation Private Limited および freee株式会社による公式見解・保証・提携を示すものではありません。