😊

Googleカレンダーの予約スケジュールの予定をスプレッドシートに転記する

に公開

はじめに

https://support.google.com/google-workspace-individual/answer/10729749?hl=ja
これで作成された予定をspreadsheetに転記してほしいと依頼があったのでツールを作成する。

  • 各自のGoogleアカウントでトリガーをセットする。
    • 自動で23時に、自分のGoogleカレンダーから予約の説明欄に「予約者」があるものをシートに転記する。
      • その際、すでにシートにあるものは転記しない。

code

main.gs
function main() {
  const sheetEventList = getEventListFromSheet();

  const eventList = CalendarApp.getDefaultCalendar().getEventsForDay(new Date()).reduce((eventList, event) => {
    const e = new Event();
    e.setDataFromGoogleCalendar(event);
    // ターゲットのイベントであり、またシートにないイベントをeventListに追加
    if (e.isTarget() && !sheetEventList.some(sheetEvent => sheetEvent.isSame(e))) eventList.push(e);
    return eventList;
  }, []);

  // シートに追記
  Shomin.addSheetLastRow(
    SHEET.calendar,
    eventList.map(e => e.getOutList())
  );
}

// 各自のGoogleアカウントで実行してもらうためトリガー作成をGASで処理する。このスクリプトと連動した画像がspreadsheetにある
function setTrigger(){
  ScriptApp.newTrigger('main').timeBased().everyDays(1).atHour(23).create();
  Browser.msgBox('トリガーを設定しました。');
}

Shominについては以下参照
https://zenn.dev/nag8/articles/e96f28dc514a04

class/Event.gs
class Event {
  constructor(event) {
    this.title;
    this.startTime = dayjs.dayjs(null);
    this.description;
  }

  setDataFromGoogleCalendar(event){
    this.title = event.getTitle();
    this.startTime = dayjs.dayjs(event.getStartTime());
    this.description = event.getDescription();
  }

  setDataFromSheet(row){
    this.title = row[SHEET.calendar.column.title - 1];
    this.startTime = dayjs.dayjs(row[SHEET.calendar.column.startTime - 1]);
    this.description = row[SHEET.calendar.column.description - 1];
  }

  isSame(event){
    return this.getTitle() === event.getTitle() && this.getStartTimeText() === event.getStartTimeText();
  }

  getTitle(){
    return this.title;
  }

  getStartTimeText(){
    return this.startTime.format('YYYY/MM/DD HH:mm');
  }

  isTarget(){
    return this.description.includes('予約者');
  }

  getOutList() {
    const descriptionTextList = this.description.split('\n');

    // 形式が変わったときにエラーにならないように念の為例外を握りつぶしている
    const getDescriptionList = _ => {
      try{
        return [
          descriptionTextList[1],
          descriptionTextList[2]
        ];
      }catch(e){
        return [
          e,
          ''
        ];
      }
    };

    return [
      this.title,
      this.getStartTimeText(),
      this.description
    ].concat(getDescriptionList());
  }
}
sheet.gs
const SHEET = {
  calendar: {
    name: 'Calendar',
    row: {
      data: 2,
    },
    column: {
      title: 1,
      startTime: 2,
      description: 3,
    },
  },
};

function getEventListFromSheet(){
  return BaseLibrary.getSheetData(SHEET.calendar).map(row => {
    const event = new Event();
    event.setDataFromSheet(row);
    return event;
  });
}

使いたい方へ

https://docs.google.com/spreadsheets/d/11-jStvOzTsPKZS7FSLW0Pzy6-KyninyZR42nmgO8kas/copy
のリンクからspreadsheetのtemplate版を自分のドライブへコピーできます。
あとは概要シートの小鳥の画像を押下したら23時に自動実行されるはずです。

結果


右端のステータス欄については依頼されていないが、あったほうがいいと思ったので追加した。データにはすべてステータスが内包されており、後続処理を考えたときにステータスの追加を主張したほうがいいことがある。


こうして書いたプログラムがみんなに運用されていくと、やりがいがありますね。

なお、過去分を一気に取り込んでもらったところ、name がとれない割合は6.14%だった。
今後直接顧客管理システムに投入する場合、この6%を少なくすることが課題になる。

ランサーズ株式会社

Discussion