支払いは絶対割り勘!そんなアナタのための支払金額計算&通知プログラム

仕事とプライベートをなんとか結び付けたいバンドマン岡村です。
の、第2弾!!
第1弾はコチラ

みなさん、割り勘してますか?
僕は割り勘します!

今回はバンド専用クレジットカード毎月の支払金額を割り勘にしてdiscordに結果を通知するプログラムを作ってみました。
登録するだけで使える既存のbotの利用も考えましたが、細かい設定をすると有料になってしまったりするので自前でチャレンジです!

やりたいことを実現するために以下の処理が必要と考えられました。

  • カード会社の支払金額通知メールから支払日と金額を取得。
  • メンバーの人数で割る。
  • 計算結果の小数点は切り上げ。
  • 計算結果が1000より小さかった場合は1000円とする(コツコツ貯金♪ということもありますが振り込みやすいため)。
  • 毎月20日12時にdiscordに今月の支払いに関する情報を通知する。
このような文面のメールから支払日や金額を取得する。

今回もソースコードのコピペと若干の編集で運用できます。
それでは作っていきましょう!

discord事前準備

  1. メッセージ送信を行いたいdiscordチャンネルのwebhookを取得。
  2. 「チャンネルの編集」をクリック。
  3. 「ウェブフックを作成」をクリック。
  4. 「ウェブフックURLをコピー」をクリックし、コピーした内容をどこかに保管しておく。
  5. 「お名前」を変更するとbotの名前を変更できます。

Google Apps Script事前準備

  1. 「新しいプロジェクト」をクリック。
  2. プロジェクトに名前を付ける。支払金額を通知するのでNoticePayment。
  3. ファイルにも名前を付ける。1つのファイルに収まりそうだったのでこちらもNoticePayment。

コーディング

ソースコードサンプルは以下。

// ディスコードのウェブフックURLにリクエストし、カードの振込金額を通知するメソッド
function noticePayment() {
  // 状況によって修正が必要な値
  const from = 'hoge@greenwich.co.jp'; // 本番時に取得するメールの送信者条件
  // const from = 'moge@greenwich.co.jp'; // テスト時に取得するメールの送信者条件
  const members = 3; // 現状のメンバー数
  const mailSubject = 'お支払金額のお知らせ'; // 取得するメール件名の条件
  const webhook = "https://discord.com/api/webhooks/hoge/moge"; // discordのウェブフックURL

  // 取得範囲となる現在より1カ月前の日付を取得
  const today = new Date();
  var after = new Date();
  const month = today.getMonth() + 1; // 現在の「月」を取得、getMonthの返り値が0~11なので+1 
  after.setMonth(month - 2); // 1カ月前の月を設定するため「月」から-2の値をセット 
  after = Utilities.formatDate(after, "Asia/Tokyo", "yyyy/MM/dd"); // フォーマットを変換

  var query = 'from:' + from + ' subject:' + mailSubject + ' after:' + after; // 取得するメールの条件
  const gmailThreads = GmailApp.search(query); // GmailThreadの配列取得

  // 条件に該当するメールがなければメソッド終了
  if (gmailThreads.length == 0) {
    return
  }

  // 取得したGmailThreadの要素数だけ繰り返し
  gmailThreads.forEach(function (gmailThread) {
    const messages = gmailThread.getMessages(); // GmailMessageの配列を取得

    // mapメソッドでmessages配列内のすべての要素に対して同じ処理を加え、新しいrequests配列を返す
    const requests = messages.map(function (message) {

      // 通知内容を作成
      var content = 'カードの支払日と支払額をお知らせするんだメナ:leaves:\r振込めたら教えてほしいんだメナ!'; // 通常表示する内容
      const plainBody = message.getPlainBody(); // HTML形式を使用しない本文を全文取得

      const payday = plainBody.match(/[0-9]{1,}月[0-9]{1,}日/); // 本文から支払日を抽出
      var totalPayment = plainBody.match(/[0-9]{1,},[0-9]{1,}円/); // 本文から支払額合計を抽出
      const replaceWord = /,|円/g; // カンマと円を複数回検索する正規表現
      totalPayment = totalPayment[0].replace(replaceWord, ''); // カンマと円を空白に置換
      totalPayment = Number(totalPayment); // 数値に変換
      const calculationResult = totalPayment / members; // 支払額合計をメンバー数で割る
      const ceilResult = Math.ceil(calculationResult); // 小数点以下は切り上げ 
      const calculation = String(totalPayment + '÷' + members + '=' + ceilResult); // 計算内容を文字列に
      var perPersonPayment = Math.ceil(ceilResult / 1000) * 1000; // 1000より小さい端数は切り上げた値を1人あたりの金額とする

      // discordにリクエストするPOST本文を作成
      const request = {
        content: content, // 通常表示のメッセージ
        embeds: [{
          // カスタム可能な埋め込みメッセージ
          fields: [
            {
              name: "支払日",
              value: payday[0]
            },
            {
              name: "支払額合計",
              value: totalPayment + '円'
            },
            {
              name: "メンバー数",
              value: members + '人'
            },
            {
              name: "計算内容",
              value: calculation
            },
            {
              name: "1人あたり",
              value: perPersonPayment + '円(振込のため1000円より小さい端数切り上げ)'
            },
          ],
          color: 6023366 // 16進数のカラーコードを10進数に変換する必要あり
        }],
      }

      return {
        url: webhook,
        contentType: 'application/json',
        payload: JSON.stringify(request),
      }
    })
    UrlFetchApp.fetchAll(requests); // 任意の詳細パラメータを使用して、複数のURLを取得する複数のリクエストを実行
  })
}

実際に運用する際に変更が必要な個所は以下です。

  1. 「本番時に取得するメールの送信者条件」のコメントがある行の代入は、支払金額通知メールの送信元のアドレスに変更。
  2. 「テスト時に取得するメールの送信者条件」のコメントがある行の代入は、テストに使う送信元と仮定したい自前のメールアドレスに変更。
  3. 「現状のメンバー数」のコメントがある行の代入は、支払金額を何人で割りたいかによって変更。
  4. 「取得するメール件名の条件」のコメントがある行の代入は、支払金額通知メールの件名に変更。
  5. 「discordのウェブフックURL」のコメントがある行の代入は、メッセージを送信したいチャンネルのウェブフックURLに変更。
  6. 「通常表示する内容」のコメントがある行の代入は、botに最初にしゃべらせたい内容に変更。絵文字も行けて、このサンプルでは葉っぱの絵文字です。
  7. 「value: payday[0]」としているところは、メール本文内に「〇月〇日」のような日付を表す文字列が複数あり、取得したい日付が1つ目の場合は[0]のままで良いが、2つ目の場合は[1]に変更。3つ目の場合は[2]に変更。4つ目以降の場合も同様。

テスト

以下の方法でメッセージ送信や計算結果、レイアウトの確認をしました。

  1. 「本番時に取得するメールの送信者条件」のコメントがある行をいったんコメントアウト。
  2. 「テスト時に取得するメールの送信者条件」のコメントがある行をいったんコメントアウト解除。
  3. 実際に取得したいメールの件名と文面をコピペしたメールを作成し、自前のメールアドレスから送信します。
  4. 実行ボタンからプログラムを実行するとdiscordに通知が来ます。

トリガーの設定

以下のように設定することで、毎月20日の午後12時から1時の間にプログラムが動くようになりメッセージが送信されます。

  1. 画面左端の時計マークをクリック。
  2. 「トリガーを追加」をクリック。
  3. 設定していく。
    • 実行する関数を選択→noticePayment
    • 時間ベースのトリガーのタイプを選択→月ベースのタイマー
    • 日を選択→20日
    • 時刻を選択→午後12時~1時
  4. 保存

完成

以下の画像のように時間通りにメッセージが送信されます。
午後12時~1時という設定なので、ピッタリではなくある程度時間がたってから来るようですね。

注意点

  • メール送信元のアドレス、件名、文面が限定されているので、カード会社側で変更があった場合は修正が必要です。
  • メンバーの人数が変わった場合も修正が必要です。

あとがき

いかがでしたでしょうか。

今回、作っていて特に面白いなと思ったのは、discord内でのメッセージ表示方法に非常に柔軟性があったことです。
コチラのページが分かりやすかったので参考にしながらレイアウトしました。
通常のメッセージ送信だけでなく、埋め込みを作ったり、項目を作ったり、色を付けたり、絵文字を付けたり…bot感がマシマシで良いですね。

さてさて、bot完成により毎月5分の時間が浮いてしまったわけですが。
岡村はこの時間を有効活用し、"ぼっち・ざ・ろっく!"の3周目に行って参ります。

また何か作ったら共有します!

お問い合わせ

サービスに関するご相談やご質問などこちらからお問い合わせください。

03-55107260

受付時間 10:00〜17:00