HapInS Developers Blog

HapInSが提供するエンジニアリングの情報サイト

売上管理に役立つ!Googleスプレッドシートでフリマアプリの売上データを簡単に整理

HapInSアドベントカレンダー2024、21日目!Skyjayのガオガエンに触発されて猛特訓していますが一向に上手くなる気配の無いponです!

はじめに

皆さんはアプリやWebページなどでフリマサービスを利用されていますか?
今回はGoogleスプレッドシートを活用して売上管理する方法をご紹介したいと思います。

Googleスプレッドシートを利用するメリット

スプレッドシートで売上管理をするメリットは多くありますが、取り急ぎ一般的には以下のメリットがあげられます。そんなんええからはよって方はスッ飛ばしてください。

無料で使える

GoogleスプレッドシートGmailアカウントさえあれば無料で利用できる点がやはり大きいです。なおかつフリマサイトの売上管理に必要な機能をすべて備えています。
月額費用がかからず、初心者でも始めやすい点が大きなメリットですね。

リアルタイムでの共有とアクセス

Googleスプレッドシートクラウドベースで動作するので、インターネットに接続していればどこからでもアクセスできます。
複数の端末(スマホタブレット、PC)から簡単にデータの更新・確認が可能です(あまりスマホで大がかりな更新はしたくないですが…)
さらに、複数人で同時に編集ができるので、チームでの売上管理にも最適です。

データの整理と分析が簡単

手動で売上データを入力し、日付やカテゴリー別に整理することで、売上傾向や商品の売れ行きなどを一目で把握できます。
Googleスプレッドシートには、数式やフィルター機能が組み込まれており、売上データを効率よく集計・分析できます(例:月別売上合計、商品の人気ランキングなど)。

売上予測と未来の計画作成

過去の売上データを元に、次月や次四半期の売上予測を立てることができます。Googleスプレッドシートの数式や関数を活用して、今後の売上目標や支出計画を立てやすくします。
(⬆︎このあたりが今回の記事の目玉です)

売上管理の自動化

スプレッドシートの「Google Apps Script」などのツールを利用すれば、手動での入力作業を自動化できます。
AppsScriptド素人だった私でも、チャッピー(ChatGPT)やジミー(Gemini)などを活用して、データ抽出を自動で行うことが出来るようになりました。

在庫管理との統合

売上管理と在庫管理を統合して、どの商品の在庫が不足しているのか、どの商品がよく売れているのかを一目で把握できます。
(⬆︎後述するサンプルには、売れ筋商品を取得するAppScriptを添付したので参考にしてみてください)

個別のコスト計算・利益分析

売上額から送料や手数料、仕入れコストを引いて、商品の利益を計算できます。利益率を計算し、最も利益の高い商品や、改善の余地がある商品を見つけ出すことができます。

セキュリティとバックアップ

Googleスプレッドシートにはデータが自動で保存され、バックアップが取られています。万が一のデータ消失に備えて、アクセス権限を管理することができ、アクセスや編集権限の付与も細かく設定できるため、セキュリティも高いです。

★個人的には、シートやセル単位での編集履歴を追えるので、トラブルがあってもロールバックできる恩恵はかなり大きいと感じています。

売上管理のサンプル

架空の商品と実在のサービス名を織り交ぜたサンプルファイルを以下に用意しました。
【サンプル】フリマ売上管理 - Google スプレッドシート

サンプルデータなし版は以下
【サンプル】フリマ売上管理_入力なし - Google スプレッドシート

ざっくり構成

行や列の構成はファイルの中身を見たら分かると思いますので割愛しますが、それぞれのシートの目的は何?って部分をまず説明します。

シート名 用途
transaction 在庫商品の情報を記録しておくシート
sales 売れた商品の情報を記録しておくシート
stats 月ごとの利益、売れ筋商品を俯瞰できるシート

(余談ですが、ブログ記事内にテーブルを挿入する際はエクセルシートをHTMLテーブルに変換しちゃう君 (ββ) を利用すると便利です)

基本的な使い方としては、商品を仕入れたらtransactionシートに情報を入力し、商品が売れたらsalesタブに情報を記載するだけです。

配送種別と送料について

今回のサンプルファイルでは、販路(フリマアプリの売り場)はメルカリとY!フリマ、ヤフオクとしています。ご自身が利用されるフリマアプリと異なる場合は、別途設定変更をお願いします。

上記アプリでは、日本郵便クロネコヤマトのどちらかで発送する想定で、おおまかに以下のように商品サイズと送料の設定をしています。

配送種別 商品名 配送
XS ゆうパケットポストmini 日本郵便
S ゆうパケットポスト 日本郵便
M 宅急便コンパクト クロネコヤマト
L(60サイズ) ゆうパック or 宅急便 どちらも
LL(100サイズ) ゆうパック or 宅急便 どちらも

※LLの送料が¥1,070になっていますが、ヤマトで送る方が多いわって方は¥1,050に置換してください。私はLLサイズほぼ使わないので日本郵便での値段にしています。

特に注目したいポイント

数式モリモリのスプレッドシートですが、私が特に使ってみてほしいポイントは以下の通りです。

赤字ライン

仕入れた商品がいくらで売れたら赤字になるのかを確認できます。サンプルファイルではtransactiionシートのP列にあるデータですね。

たとえばP23の数式はこんな感じです。

=IF(D23="", "", ($G23 + $D23) / IF(OR($E23="メルカリ", $E23="ヤフオク"), 0.9, IF($E23="Y!フリマ", 0.95, 1)))

販路によって販売手数料が異なるため、OR関数で分岐させています。
購入希望者から値下げの提案が来たけど、どのぐらいまでなら値下げに応じられるをサッと確かめたい時に便利です。
(この部分だけならまだ正直Excelでも実現出来る)

販売利益

transactionシートH列にフリマアプリでの販売額を入力すると、仕入額、販路に応じて販売手数料と送料を差し引いた利益を教えてくれます。

=ROUNDUP($H23*IF(OR($E23="メルカリ", $E23="ヤフオク"), 0.9, IF($E23="Y!フリマ", 0.95, 1))-$G23-$D23, 0)

数式内でROUNDUPを使用しているのは、メルカリとY!フリマなどでは小数点切り上げで売り上げが計算されているためです。初期にスプレッドシートを運用していた頃、「どうしても1円合わないんだが…?」ということがあってからこの設定を適用しています。

また、メルカリでは5%、10%、15%のタイムセール設定があるので、メルカリユーザ向けに値下げした場合の列を設けています。

月毎の集計

statsシートには月間仕入額、月間売上が表示されていますが、こちらはあくまで販売完了したものをターゲットにしているため、在庫は計上されていません。

売れ筋商品

ここはAppScriptで実装しています。 statsシートのAB列いずれかの編集をトリガーとして、最もよく売れている商品の配送種別と回数を表示するようにしています。

最高値と最高値商品

ここもAppScriptですが、各月で最も高く売れた商品の値段と、その商品の名前を取得して表示するようにしています。

App Script

上記、売れ筋商品や最高値の商品と値段などを抽出していますが、以下のAppScriptで取得しています。

function processData(sheetName) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const statsSheet = ss.getSheetByName(sheetName || 'stats');
  const salesSheet = ss.getSheetByName('sales');

  // statsシートのAB列とD列のデータを取得
  const statsData = statsSheet.getRange(4, 1, statsSheet.getLastRow() - 3, 4).getValues();

  // salesシートのデータを取得(A列、D列、G列、I列、J列)
  const salesData = salesSheet.getRange(2, 1, salesSheet.getLastRow() - 1, 10).getValues();

  statsData.forEach((row, index) => {
    const year = row[0];
    const month = row[1];

    // AB列にデータがない行はスキップ
    if (!year || !month) return;

    const yearMonth = Utilities.formatDate(new Date(year, month - 1, 1), Session.getScriptTimeZone(), 'yyyy/MM');
    let maxSaleAmount = -1;
    let highestPriceProductName = '';
    let deliveryCountMap = {};

    salesData.forEach(saleRow => {
      const itemName = saleRow[0]; // 品名
      const salesDate = saleRow[8]; // 販売完了日
      const deliveryType = saleRow[6]; // 配送種別
      const saleAmount = saleRow[9]; // 販売額

      // 年月が一致する場合のみ処理
      if (salesDate && Utilities.formatDate(new Date(salesDate), Session.getScriptTimeZone(), 'yyyy/MM') === yearMonth) {
        // 最高販売額とその商品の品名を取得
        if (saleAmount > maxSaleAmount) {
          maxSaleAmount = saleAmount;
          highestPriceProductName = itemName;
        }

        // 配送種別のカウント
        if (deliveryType) {
          deliveryCountMap[deliveryType] = (deliveryCountMap[deliveryType] || 0) + 1;
        }
      }
    });

    // 配送種別の最頻出と2番目の頻出を取得
    const sortedTypes = Object.entries(deliveryCountMap).sort((a, b) => b[1] - a[1]);
    const mostFrequentType = sortedTypes[0] ? sortedTypes[0][0] : "-";
    const secondFrequentType = sortedTypes[1] ? sortedTypes[1][0] : "-";

    // 結果の出力
    statsSheet.getRange(index + 4, 7).setValue(mostFrequentType); // G列に最頻出配送種別
    statsSheet.getRange(index + 4, 9).setValue(secondFrequentType); // I列に2番目に頻出配送種別
    statsSheet.getRange(index + 4, 11).setValue(maxSaleAmount === -1 ? '-' : maxSaleAmount); // K列に最も高値で売れた商品の販売額
    statsSheet.getRange(index + 4, 12).setValue(highestPriceProductName || '-'); // L列に最も高値で売れた商品の品名
  });
}

function onEditTrigger(e) {
  const sheet = e.range.getSheet();
  if (sheet.getName() === "stats" && e.range.columnStart >= 1 && e.range.columnStart <= 2) {
    processData("stats");
  }
}

サンプルファイルをダウンロードして利用する際、上記スクリプトを有効化するにはApp Scriptのトリガーを設定しないと使えません。

トリガーの設定方法

スプレッドシートの以下の設定をたどります。

拡張機能>App Script
サイドバー>トリガー>トリガーを追加
添付画像のように設定し、保存

まとめ

いかがでしたでしょうか?
今回は主にメルカリとY!フリマに特化したサンプルでしたが、ご紹介したスプレッドシートを使って個人での売り上げを可視化してみませんか?
「●●バージョンも作ってほしい!」などリクエストありましたら、別途作ってみますのでコメント頂けますと幸いです。