ck_fm0211のブログ

書きたいことを書く。

ギガ活で得たプロモコードをスプレッドシートで管理するGASを書いた

はじめに

今月から携帯電話のプランをpovo2.0に変更した。 povo.jp

ほとんどフルリモートワークで家にいることが多く、外に出てもそれほどスマホで通信しない(ドラクエウォークをするくらい)。
そのため月の通信量も3GBもあれば十分だろうと判断した。
povo2.0は基本料がゼロ円で、データ通信量をトッピングという形で追加していく。

月に3GBくらいの利用量だと、 3GB(30日間)で990円というトッピングをつけることになる。
また、ちょっと遠出したり、イベントがあって今日はスマホをたくさん使う、みたいなときはデータ使い放題(24時間)で330円というトッピングもあり、利用状況に応じて柔軟に設定できそうだなと思ったので契約した。

使いはじめて早速、ギガ活で無料通信量をもらったのだが、そのためのプロモコード管理がちょっと面倒だった。
ちょっとでも楽をするためにGoogle Apps Script(GAS)を書いたのでここで紹介する。

ギガ活

実装内容の前にギガ活とはなんぞやという話。

povo2.0の真価はプラン設定の柔軟さだけではなく、ギガ活というキャンペーンにあると思っている。 povo.jp

公式ページからの引用。

ギガそのものを購入する体験とは違う新しいギガのチャージ活動です。
#ギガ活でもらう。#ギガ活でさがす。#ギガ活であたる。
日常のあらゆる接点の中でギガを受け取ったり、探したりできるような世界を目指しています。

要は、ポイントカードにポイントを貯めるように、無料で使える通信量を貯められる、という感じ。
その条件も「ローソンでau Pay(コード決済)で500円以上の決済をする」というようなもので、喫煙者の自分としてはタバコ一箱買うだけで300MB(3日間)がもらえる。
生活スタイルと合致すれば、ほぼゼロ円で運用ができてしまう。

報酬の通信量はプロモコードという形でメールが送られてくるのだが、そこにいくつか不便な点が。

  1. 条件達成から即時プロモコードを貰えるわけではなく、一定期間で達成した分がまとめてメールで送られてくる。
  2. プロモコードには有効期限があり、概ね発行の翌月末が設定されている(と思われる)

そのため、1週間に何度も条件を達成するとまとめてプロモコードが送られてきて、そのうちどれを利用してどれが未使用かがわからなくなってしまう。
これを解決したいがためにGASを書いた。*1

実装内容

処理の流れとしては以下の通り。

  1. Gmailでメールを受信し、その際 00_ギガ活 というラベルを付ける
  2. GAS(タイマー起動)で上記ラベルがついているメールを取得し、そこから正規表現でプロモコードを抽出する
  3. 抽出したプロモコードをスプレッドシートに書き込む
  4. 処理したメールに 00_ギガ活/処理済み というラベルを付ける

できたコードが以下。

/**
 * ギガ活のメールからコードを抽出し、スプレッドシートに書き出す
 */

// スプレッドシート
const sheet = SpreadsheetApp.getActive().getSheetByName('コード一覧');

/**
 * 本体
 * 1. ギガ活のラベルがついたメールを抽出
 * 2. メール本文からプロモコードと利用期限を抽出
 * 3. スプレッドシートに記入
 * 4. 処理したメールに処理済みラベルを付与
 */
function getPromotionCodes() {
  
  console.log("[START]メール取得");
  // 検索条件に該当するスレッド一覧を取得
  let threads = GmailApp.search('label:00_ギガ活  -label:00_ギガ活/処理済み');

  console.log("[START]スレッド処理");  
  // スレッドを一つずつ取り出す
  threads.forEach(function(thread) {
    // スレッド内のメール一覧を取得
    let messages = thread.getMessages();
    
    // メールを一つずつ取り出す
    messages.forEach(function(message) {
      // メールからコード値と利用期限を抽出する
      let values = extractCode(message)
      // メールを処理しているのにプロモコードが取れなかったらアラート
      if(values["codes"].length === 0){
        console.log("[ERROR]データ抽出");
        throw new Error("プロモコードの抽出に失敗しました")
      }
      // スプレッドシートに書き出す
      console.log("[START]スプレッドシート書き込み");
      writeSheet(values)
    });

    // スプレッドシートに条件付き書式を設定
    console.log("[START]条件付き書式更新");
    upsertConditionalFormatRule()    

    // スレッドに処理済みラベルを付ける
    console.log("[START]ラベル追加");
    let label = GmailApp.getUserLabelByName('00_ギガ活/処理済み');
    thread.addLabel(label);
  });
}

/**
 * メール本文からプロモコードと利用期限、メール受信日を抽出
 * 抽出する際、プロモコードは<strong>タグの中にあるため、html形式のbodyから正規表現で抽出する
 * 入力期限は「コードの入力期限」というメッセージのあとに記載されているため、プレーンテキストのメールbodyから抽出する
 */
function extractCode(message){
  let body = message.getBody();
  let plainBody = message.getPlainBody();

  let ret = {};

  // 形式:300MBXXXXXXXXX
  let codes = body.match(/([1-9]{1}[A-Z0-9]{13})(?=.*<\/strong>)/g);
  ret["codes"] = codes;
  // 入力期限
  let limitDate = plainBody.match(/(?<=コードの入力期限\n*)20[0-9]{2}\/[0-9]{2}\/[0-9]{2}/g);
  ret["limitDate"] = limitDate;
  // 受信日
  let receiveDate = message.getDate();
  ret["receiveDate"] = receiveDate;
  return ret;
}

/**
 * スプレッドシートに書き込む
 */
function writeSheet(values){
  // 処理日
  const today = new Date();

  // 最終行を取得
  let lastRow = sheet.getLastRow() + 1;

  // セルを取得して値を転記
  let index = 0
  for(let code of values["codes"]){
    sheet.getRange(lastRow + index, 1).setValue(today);                  // 記入日
    sheet.getRange(lastRow + index, 2).setValue(values["receiveDate"]);  // メール受信日
    sheet.getRange(lastRow + index, 3).setValue(code);                   // プロモコード
    // sheet.getRange(lastRow + index, 4).setValue(email[1]);            // 容量 ※コードの仕様がわからんと入れられない
    sheet.getRange(lastRow + index, 5).setValue(values["limitDate"]);    // 使用期限 
    sheet.getRange(lastRow + index, 6).insertCheckboxes();               // 使用済みチェックボックス
    index += 1;
  }
}

/**
 * スプレッドシートに条件付き書式を設定する
 * 条件:使用済み列(F列)がTRUE(チェックON) 書式: グレーアウト
 */
function upsertConditionalFormatRule(){
  let conditionalFormatRule = SpreadsheetApp.newConditionalFormatRule()
  .whenFormulaSatisfied('=$F1=TRUE')
  .setBackground('#B7B7B7')
  .setRanges([sheet.getRange(1,1,sheet.getLastRow() + 1, 6)])
  .build()
  let conditionalFormatRules = sheet.getConditionalFormatRules();
  if(conditionalFormatRules.length > 0){
    // 既存の条件付き書式と差し替え
    conditionalFormatRules.splice(conditionalFormatRules.length - 1, 1, conditionalFormatRule);
  }else{
    // 初回起動時には条件付き書式がないので直接push
    conditionalFormatRules.push(conditionalFormatRule)
  }
  // 条件付き書式を設定
  sheet.setConditionalFormatRules(conditionalFormatRules);
}

これをGASのトリガーで一日2回動かしている。
で、スプレッドシートは以下のような形で作成。プロモコードと有効期限、使用したかどうかのチェックボックスを用意した。
普段の運用としては、通信量をチャージしたいなと思ったらこれを開いてプロモコードをpovo2.0アプリに入力、最後にチェックボックスをチェックする。

f:id:ck_fm0211:20220326220429p:plain
ギガ活プロコード管理用スプレッドシート

まだ運用開始して日数が少ないため、プロモコードの正規表現のパターンがこれであってるかどうかが怪しい気もする。
これについてはしばらくは様子を見ながら運用する。

おわりに

とりあえず気軽にできるということもありGmail→GAS→スプレッドシートの仕組みを作った。
スプレッドシートよりもnotionの方が使いやすいかなという気もしているので、そっちにそのうち移行するかもしれない。
また、「利用期限が7日以内になっているものがある場合にLINEに通知する」というGASも書いた。
これもそのうち記事にするかもしれない。というか明日には書いてるかも。

なお、この記事を読んでpovo2.0いいなと思った方がいれば(そんな人がいれば)、申込時に以下の紹介コードを入力すれば、データ使い放題(24時間)が自動で適用されたり、購入したデータトッピングに応じてプロモコードを追加で貰えたりするそうなのでよかったら使ってください。
L11MWBXE

povo.jp

2022/03/27追記

「利用期限が7日以内になっているものがある場合にLINEに通知する」というGASも書いた。
これもそのうち記事にするかもしれない。というか明日には書いてるかも。

記事にするのが面倒だったのでGitHubに上げることで供養。

github.com

*1:Androidスマホだと管理用アプリもあったりする。自分はiPhoneなので利用できないが。。rironriron.web.app