Google App Script 自動化

【GAS】注文リスト自動作成&Googleカレンダ自動登録(1)

はじめに

これまで、楽天市場、Amazon、GooglePlayで注文した際に送られてくる注文確認メールの内容を元に、

  • 自動的にカレンダーに登録
  • 自動的に注文リスト作成

する処理をこれまで説明してきました。

今回は、これらの処理をまとめて一つにして、受信する注文確認メールの仕様変更時などに、容易に対応できるようにします。

対象読者

ここで紹介する内容は、以下の条件を満たす方が対象となります。

対象読者

  • 楽天市場、Amazon、GooglePlayを使って注文することがある
  • 注文内容確認メールをGmailで受け取っている
  • 注文内容をGoogleカレンダーに自動登録し、スプレッドシートにも自動追加したい

これまでの復習

ここでは、以下の6つの処理を一つにまとめることを考えます。

  • 楽天市場の注文内容をGoogleカレンダーに自動登録
  • 楽天市場の注文内容リストを自動作成
  • Amazonの注文内容をGoogleカレンダーに自動登録
  • Amazonの注文内容リストを自動作成
  • GooglePlayの注文内容をGoogleカレンダーに自動登録
  • GooglePlayの注文内容リストを自動作成

それぞれ記事を起こしていますので、見直しておくとわかりやすいかと思います。

読み飛ばしていただいても問題ありません。

処理概要

処理概要としては以下の通りです。

  • 「未読」で「自動処理済」のラベルをついていないメールを抽出
  • 楽天市場、Amazon、GooglePlayの注文確認メールか確認
  • カレンダー登録及び注文リスト登録処理実行
  • 処理したメールに「自動処理済」のラベル付与

楽天市場、Amazon、GooglePlayそれぞれから受信した注文確認メールの内容解析は、別々のライブラリとして処理を実装します。

今回使用するライブラリは、

  • カレンダー登録ライブラリ(libCtrlCalendar)
  • メールにラベルを付けるライブラリ(libCtrlMail)
  • 注文リストに注文内容を追加するライブラリ(libAddOrderToList)

となります。

カレンダー登録ライブラリ(libCtrlCalendar)、メールにラベルを付けるライブラリ(libCtrlMail)、注文リストに注文内容を追加するライブラリ(libAddOrderToList)については以下の記事を参照ください。

全てのコード

楽天市場、Amazon、GooglePlayのメールを解析する処理は以下の通り別々のライブラリとして実装します。

  • 楽天市場 注文確認メール解析登録処理:libManageRakutenOrder
  • Amazon 注文確認メール解析登録処理:libManageAmazonOrder
  • GooglePlay 注文確認メール解析登録処理:libManageGooglePlayOrder

今回は、まずこれらのライブラリを呼び出すメインの処理を用意します。

libManageXXXXOrderライブラリは次回の記事で説明します。

/*
 * 楽天市場、Amazon、Google Playの注文リストを作成し、Googleカレンダーに登録する
 * 2021/12/04 Created by N.Sekiya
 *
 * <使用ライブラリ>
 * ・カレンダー登録ライブラリ(libCtrlCalendar)
 * ・メールにラベルを付けるライブラリ(libCtrlMail)
 * ・注文リスト追加ライブラリ(libAddOrderToList)
 * ・楽天市場 注文確認メール処理(libManageRakutenOrder)
 * ・Amazon 注文確認メール処理(libManageAmazonOrder)
 * ・GooglePlay 注文確認メール処理(libManageGooglePlayOrder)
 */

// 処理済み後に付けるラベル名(ラベルが存在しなければ自動的に作られる)
var LABEL = '自動処理済';

// 注文リストファイル名(スプレッドシートファイル名)
var ORDER_LIST_FILE = 'OrderList';

// GMail検索文字列(未読でラベルなしが条件)
var SEARCH_QUERY = 'is:unread -label:' + LABEL;

// 楽天市場からの注文確認メール識別用
var MAIL_FROM_RAKUTEN = 'order@rakuten.co.jp';
var MAIL_SUBJECT_RAKUTEN = '【楽天市場】注文内容ご確認';

// Amazonからの注文確認メール識別用
var MAIL_FROM_AMAZON = 'digital-no-reply@amazon.co.jp';
var MAIL_SUBJECT_AMAZON = 'ご注文';

// GooglePlayからの注文確認メール識別用
var MAIL_FROM_GOOGLEPLAY = 'googleplay-noreply@google.com';
var MAIL_SUBJECT_GOOGLEPLAY = 'Your Google Play Order Receipt from'

function OrderManagement() {

  // メールを取得
  var threads = GmailApp.search(SEARCH_QUERY, 0, 10);
  if (threads.length === 0) {
    Logger.log('メールが見つかりません');
    return;
  }

  // デフォルトカレンダーを取得
  var calendar = CalendarApp.getDefaultCalendar();

  for(var k in threads){
    var thread = threads[k]
    var messages = thread.getMessages();
    for (var j in messages){
      
      var message = messages[j];
      var mailFrom = message.getFrom();
      var mailSubject = message.getSubject();
      //Logger.log('From: ' + mailFrom + 'subject:' + mailSubject);

      if(mailFrom.indexOf(MAIL_FROM_RAKUTEN) >= 0 && mailSubject.indexOf(MAIL_SUBJECT_RAKUTEN) >= 0){

        // 楽天注文確認メール処理
        Logger.log('>>楽天市場注文確認処理');
        Logger.log('From: ' + mailFrom + 'subject:' + mailSubject);
        libManageRakutenOrder.register(message, calendar, ORDER_LIST_FILE);
        libCtrlMail.putLabel(thread);   // 処理済みラベルを付ける
      }
      else if(mailFrom.indexOf(MAIL_FROM_AMAZON) >= 0 && mailSubject.indexOf(MAIL_SUBJECT_AMAZON) >= 0){

        // Amazon注文確認メール処理
        Logger.log('>>Amazon注文確認処理');
        Logger.log('From: ' + mailFrom + 'subject:' + mailSubject);   
        libManageAmazonOrder.register(message, calendar, ORDER_LIST_FILE);
        libCtrlMail.putLabel(thread);     // 処理済みラベルを付ける   
      }
      else if(mailFrom.indexOf(MAIL_FROM_GOOGLEPLAY) >= 0 && mailSubject.indexOf(MAIL_SUBJECT_GOOGLEPLAY) >= 0){

        // GooglePlay注文確認処理
        Logger.log('>>GooglePlay注文処理');
        Logger.log('From: ' + mailFrom + 'subject:' + mailSubject);
        libManageGooglePlayOrder.register(message, calendar, ORDER_LIST_FILE);
        libCtrlMail.putLabel(thread);     // 処理済みラベルを付ける
      }
    }
  }
}

カレンダー、メール、注文リストライブラリ全てのコード

念のため、カレンダー(libCtrlCalendar)、メール(libCtrlMail)、注文リスト(libAddOrderToList)ライブラリのすべてのコードを掲載しておきます。

カレンダー処理ライブラリ(libCtrlCalendar)

ファイル名(ライブラリ名):libCtrlCalendar

/*
 * Google Calendarに登録
 * 
 */
function registCalendar(calendar, title, startTime, endTime, contents, color){
  if (title && startTime && endTime && contents) {

    // カレンダーに追加
    if(checkExist_(calendar, title, startTime, endTime) == false){
      var options = {
        description : contents
      }
      var event = calendar.createEvent(title, startTime, endTime, options);
      event.setColor(color);
      event.removeAllReminders();   // 利用実績なので通知しない
    }
  }  
}

/*
 * カレンダーに登録済みイベントがあるかチェック
 * 
 */
function checkExist_(calendar, registTitle, registStart, registEnd){

  // イベントリスト取得
  var events = calendar.getEvents(registStart, registEnd);
  for(const event of events){
    var title = event.getTitle();
    if(title.indexOf(registTitle) >= 0){
      return true;    // イベント登録済み
    }
  }
  // イベント未登録
  return false;
}

メール処理ライブラリ(libCtrlMail)

ファイル名(ライブラリ名):libCtrlMail.gas

/*
 * 処理済みとしてスレッドにラベルを付ける
 * 
 * LABELで指定されるラベルが存在しない場合は作成する
 */

// 処理済み後に付けるラベル名(ラベルが存在しなければ自動的に作られる)
var LABEL = '自動処理済';

function putLabel(thread){
  var label = GmailApp.getUserLabelByName(LABEL);
  if(label){
    thread.addLabel(label);
    Logger.log('既存ラベル使用');
  }
  else{
    var newlabel = GmailApp.createLabel(LABEL);
    thread.addLabel(newlabel);
    Logger.log('新規ラベル追加');
  }
}

注文リスト追加ライブラリ(libAddOrderToList)

ファイル名(ライブラリ名):libAddOrderToList.gas

/*
 * libAddOrderToList
 * 
 * 注文情報をスプレッドシートに追記するライブラリ
 * 
 * 2021/10/27 created by N.Sekiya
 */

var FOLDER_NAME = '40_仕事関係';
var FILE_NAME = 'test';

function test(){
  registOderInfoToSpreadSheet(
    FILE_NAME, FOLDER_NAME,
    new Date(),
    '楽天市場',
    '【クーポン利用で21980円】高コスパ 10.1インチ Android10.0 8コア SIMフリー 4G LTE通信 大画面',
    23980,
    1,
    21980,
    '東京博海 楽天市場店'
  );
}

function registOderInfoToSpreadSheet(fileName, folderName,
  orderDate, ecSite, item, price, count, shop){

  //Logger.log('filename=' + fileName);
  //Logger.log('folderName=' + folderName);
  Logger.log('orderDate=' + orderDate + ' ec=' + ecSite);
  Logger.log('item=' + item);
  Logger.log('price=' + price + ' cnt=' + count + ' shop=' + shop);
  
  var ss = null;
  if(fileExists_(fileName, folderName)){
    var files = DriveApp.getRootFolder().getFilesByName(fileName); 
    ss = files.next();
    masterSheet = openSpreadSheet_(ss);
  }
  else{
    ss = createSpreadSheet_(fileName, folderName);
    masterSheet = openSpreadSheet_(ss);
    initializeSpreadSheet_(masterSheet);  
  }

  var no = 1;
  var val = getValue_(masterSheet, no, 1);
  while(val != ''){
    no++;
    val = getValue_(masterSheet, no, 1);
  }

  // スプレッドシートの最終行に追加
  masterSheet.appendRow([
        no-1, orderDate, ecSite, item, price, count, 0, 0, 0, 0, 0, shop]);
}

function registOderInfoToSpreadSheetSub(
  fileName, folderName, shipping, point_used, coupon_used, payment, point_get){
  
  Logger.log('shipping=' + shipping + ' point_used=' + point_used + 
  ' coupon_used=' + coupon_used + ' payment=' + payment + ' point_get=' + point_get);

  var ss = null;
  if(fileExists_(fileName, folderName)){
    var files = DriveApp.getRootFolder().getFilesByName(fileName); 
    ss = files.next();
    masterSheet = openSpreadSheet_(ss);
  }
  else{
    return;   // fileNameのファイルがない場合は処理しない
  }

  var no = 1;
  var val = getValue_(masterSheet, no, 1);
  while(val != ''){
    no++;
    val = getValue_(masterSheet, no, 1);
  }

  // スプレッドシートの最終行に追加
  setValue_(masterSheet, no-1, 7, shipping);
  setValue_(masterSheet, no-1, 8, point_used);
  setValue_(masterSheet, no-1, 9, coupon_used);
  setValue_(masterSheet, no-1, 10, payment);
  setValue_(masterSheet, no-1, 11, point_get);
}

/*
 * 新規スプレッドシート作成
 */
function createSpreadSheet_(fileName, folderName) {

  // 新規スプレッドシート作成
  var ss = SpreadsheetApp.create(fileName);
  var org = DriveApp.getFileById(ss.getId());

  // 指定フォルダに移動
//  const id = getFolder(folderName).getId();
//  DriveApp.getFolderById(id).addFile(org);
//  DriveApp.getRootFolder().removeFile(org);

  return org;
}

/*
 * スプレッドシートファイルを開き、最初のシートを選択する
 */
function openSpreadSheet_(ss){

    var ssId = ss.getId();
    var ssFile = SpreadsheetApp.openById(ssId);
    var activeSpreadSheet = SpreadsheetApp.setActiveSpreadsheet(ssFile);
    var masterSheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];

    return masterSheet;
}

/*
 * スプレッドシートにヘッダをつける
 */
function initializeSpreadSheet_(masterSheet){
  masterSheet.appendRow([
      'No', '購入日', 'ECサイト', '商品', '値段', '数量', '送料', 
      'ポイント使用', 'クーポン使用', '支払額', '獲得ポイント', 'ショップ名']);
}

/*
 * ファイル存在チェック
 */
function fileExists_(fileName, folderName) {
//  var folder = getFolder(folderName);
//  var files = folder.getFilesByName(fileName);
  var files = DriveApp.getRootFolder().getFilesByName(fileName);
  
  while (files.hasNext()) {
    var file = files.next();
    if(fileName == file.getName()) {
      return true;
    }
  }
  return false;
}

/*
 * フォルダ名からフォルダ取得
 */
function getFolder_(folderName) {
  var folders = DriveApp.getFoldersByName(folderName);
  while(folders.hasNext()) {
    var folder = folders.next();
    if(folder.getName() == folderName){
      break;
    }
  }
  return folder;
}

/*
 * スプレッドシートsheetのrow, colから値取得
 */
function getValue_(sheet,row,col) {
  var value = sheet.getRange(row, col).getValue();
  return value;
}

/*
 * スプレッドシートsheetのrow, colに値設定
 */
function setValue_(sheet,row,col,value){
  var cell = sheet.getRange(row,col);
  cell.setValue(value);
}

まとめ

コードばかりですが、基本コピペで行けます。

次回に楽天市場、Amazon、GooglePlayのメール解析処理を掲載します。

では、今日も良い一日を。

-Google App Script, 自動化
-, , , , , , ,