GmailSpreadSheet

【GAS】スプレッドシートに書き込み メール添付の請求書PDFを保存してチャットに通知⑩

前回のおさらい

前々回と前回はslackとchatworkという2つのチャットツールに通知メッセージを投稿できるようにしました。


それぞれ、slackAPI、chatworkAPIを利用する関数をつくって、本体のプログラムから呼び出すようにしました。

sendSlack関数 ※slackにメッセージを投稿する関数

const sendSlack = chatMessage => {
  const endpoint = 'https://slack.com/api/chat.postMessage'
  const token = 'トークンが入ります'
  const channel = 'チャンネルIDが入ります'
  const text = chatMessage
  const payload = {
    token, channel, text
  }
  const options = {
    method: 'POST',
    payload,
  }
  const response = UrlFetchApp.fetch(endpoint, options)
  console.log(response.getResponseCode())
}


sendChatwork関数 ※chatworkにメッセージを投稿する関数

const sendChatwork = chatMessage => {
  // endpointの定義
  const roomId = 'ルームIDが入ります'
  const endpoint = `https://api.chatwork.com/v2/rooms/${roomId}/messages`

  // APIトークン
  const token = 'APIトークンが入ります'

  // リクエストボディ
  const message = chatMessage

  // リクエストボディにはメッセージのみを格納
  const payload = {
    body: message,
  }

  // ヘッダーにトークンをセット
  const headers = {
    'x-chatworktoken': token,
  }

  // optionsにheaderとpayload(リクエストボディ)をセット
  const options = {
    headers, payload
  }

  const response = UrlFetchApp.fetch(endpoint, options)
  console.log(response.getResponseCode())
}


今回は経理からの要望を受けまして、税抜請求額と税込請求額をスプレッドシートに転記します。

手作業ですと必ずいつかは忘れてしまいます。

そこでGASにやらせてしまおうといった魂胆でございます。

転記用のスプレッドシートを作成する

まずは転記用のスプレッドシートを作成します。

Googleドライブの任意のフォルダをひらきます。(ここでは請求書フォルダ)


右クリックでメニューをひらいてGoogleスプレッドシートを選択


すると無題のスプレッドシートがつくられます


スプレッドシートの名前を変更して、年月、税抜請求額、税込請求額と記入

シート名は「請求額」としておきます。


Googleドライブでこのようになっていればオッケー

これで準備完了です。

次にスプレッドシートに転記するための関数をつくって、請求月、税抜請求額、税込請求額をわたしましょう

転記するための関数をつくって請求月、税抜請求額、税込請求額をわたす

searchGmail関数はこんなふうになっています。

const searchGmail = () => {
  const gmail = GmailApp
  const searchedMail = gmail.search('from:株式会社 インボイス送信元 subject: 【請求書】送付のご案内 is:unread')
  const messages = searchedMail.map(thread => {
    return thread.getMessages()
  })
  const message = messages[0][0]

  // 本文から税抜請求額と税込請求額を取得
  const messageBody = message.getPlainBody()
  const taxNotIncluded = messageBody.match(/税抜請求額.*$/m)[0]
  const taxIncluded = messageBody.match(/税込請求額.*$/m)[0]

  // 添付ファイルの取得とドライブへの保存
  const attachments = message.getAttachments()
  const drive = DriveApp
  const folder = drive.getFolderById('フォルダIDが入ります')
  const invoiceFile = folder.createFile(attachments[0])
  
  // チャット通知用メッセージの材料を集める
  const fromName = message.getFrom()
  const companyName = fromName.match(/"([^"]*)"/)[1]
  const invoiceUrl = invoiceFile.getDownloadUrl()
  
  // PDFからOCRでテキストを取り出す
  const document = Drive.Files.copy({ title: 'テスト' }, invoiceFile.getId(), { ocr: true })
  const documentApp = DocumentApp
  const documentFile = documentApp.openById(document.id)
  const documentBody = documentFile.getBody()
  const text = documentBody.getText()
  const invoiceDate = text.match(/(\d{4}年\d{1,2}月分)/)[1]
  invoiceFile.setName(`${invoiceDate} ${companyName} 請求書`)

  // 通知用のメッセージをつくる ※位置を上から移動
  const chatMessage = `${companyName}の${invoiceDate}請求書が届きました。\n${taxNotIncluded} ${taxIncluded}\n以下のURLからダウンロードしてください。\n${invoiceUrl}`
  
  // 不要なGoogleドキュメントファイルを削除する
  const removingFile = drive.getFileById(document.id)
  removingFile.setTrashed(true)

  sendChatwork(chatMessage)
  sendSlack(chatMessage)
}

上のsearchGmail関数の中のtaxNotIncluded、taxIncluded、invoiceDateがそれぞれ税抜請求額、税込請求額、請求月にあたります。

せっかく取得したのでスプレッドシートに転記するための関数にわたします。


転記するための関数には請求月、税抜請求額、税込請求額を受け取れるように引数を3つ設定します。

const insertBillingAccount = (invoiceDate, taxNotIncluded, taxIncluded) => {
  // 日付は「分」を削除、税抜請求額、税込請求額は数字のみ抜き出す
  const date = invoiceDate.replace('分', '')
  const taxNotIncludedInt = taxNotIncluded.replace('税抜請求額 ', '').replace('円', '')
  const taxIncludedInt = taxIncluded.replace('税込請求額 ', '').replace('円', '')
  console.log(date, taxNotIncludedInt, taxIncludedInt)
}


invoiceDateは「2024年3月分」となっていまして、「分」が余計なのでreplaceメソッドを使って削除します。

同様にtaxNotIncludedもtaxIncludedも数字の部分だけ抜き出したいのでreplaceメソッドを使います。

replaceメソッド ー 文字列を指定して別の文字列に置換するメソッド

構文:文字列.replace(‘置換対象の文字列’, ‘置換後の文字列’)

戻り値:文字列

参照)MDN replaceメソッド


では、ためしに実行してみます。

実行結果


ちゃんとできていますね。

では、さっきつくったスプレッドシートの書き込むセルを指定します。

スプレッドシートの書き込むセルを指定

GASでスプレッドシートを扱うためにスプレッドシートアプリをつくります。

const spreadSheetApp = SpreadsheetApp


スプレッドシートアプリからスプレッドシートのオブジェクトをつくります。

const spreadSheet = spreadSheetApp.openById('スプレッドシートIDが入ります')

openByIdメソッド ー IDを指定してスプレッドシートオブジェクトをつくるメソッド

構文:スプレッドシートアプリ.openById(‘スプレッドシートID’)

戻り値:スプレッドシートオブジェクト

参照)Google Apps Scriptのマニュアル スプレッドシートアプリクラス

スプレッドシートIDは下の赤枠内の文字列です ※下の画像ではマスクしています


ちなみにオブジェクトってのはデータとメソッド(命令)がワンセットになった便利なやつです。

概念図

次にスプレッドシートオブジェクトからシートオブジェクトを作ります。

const sheet = spreadSheet.getSheetByName('請求額')

getSheetByNameメソッド ー シート名を指定してシートオブジェクトをつくるメソッド

構文:スプレッドシートオブジェクト.getSheetByName(‘シート名’)

戻り値:シートオブジェクト

参照)Google Apps Scriptのマニュアル スプレッドシートクラス


シート名を「請求額」としましたので、getSheetByNameメソッドにわたすのは’請求額’です。

さらに書き込む範囲(セル)を指定します。

年月は1列目、税抜請求額は2列目、税込請求額は3列目です。

で、それぞれの最初の空白行に書き込むようにすれば良いというわけです。

const row = sheet.getLastRow() + 1
const dateRange = sheet.getRange(row, 1) // 日付を記入するセルを指定
const notIncludedRange = sheet.getRange(row, 2) // 税抜請求額を記入するセルを指定
const includedRange = sheet.getRange(row, 3) // 税込請求額を記入するセルを指定

getLastRowメソッド ー シートの最終行を取得するメソッド

構文:シートオブジェクト.getLastRow()

戻り値:数値

参照)Google Apps Scriptのマニュアル シートクラス

getRangeメソッド ー シートのセルを指定するメソッド

構文:シート.getRange(開始行, 開始列, 行数, 列数)

戻り値:範囲(セル)

参照)Google Apps Scriptのマニュアル シートクラス


getLastRowメソッドはシート中のデータのある最終行を取得するのでこの場合は1を値として取得できます。(なぜなら1行目にしかデータがないので)

最終行の次の行が空白なので、+1をしているんですね。

const row = sheet.getLastRow() + 1


ここまででセルの指定が完了しました。

セルの指定方法は↓でもう少し詳しく説明しています。

セルに値を記入する

さて、つくったスプレッドシートに請求月、税抜請求額、税込請求額を書き込んでいきます。

dateRange.setValue(date)
notIncludedRange.setValue(taxNotIncludedInt)
includedRange.setValue(taxIncludedInt)

setValueメソッド ー 一つのセルに値を書き込むメソッド

構文:範囲(セル).setValue(値)

戻り値:範囲(セル)

参照)Google Apps Scriptのマニュアル 範囲(セル)クラス


これで大丈夫じゃないかと思います。

スプレッドシートに転記するための関数はこうなっています。

const insertBillingAccount = (invoiceDate, taxNotIncluded, taxIncluded) => {
  // 日付は「分」を削除、税抜請求額、税込請求額は数字のみ抜き出す
  const date = invoiceDate.replace('分', '')
  const taxNotIncludedInt = taxNotIncluded.replace('税抜請求額 ', '').replace('円', '')
  const taxIncludedInt = taxIncluded.replace('税込請求額 ', '').replace('円', '')
  console.log(date, taxNotIncludedInt, taxIncludedInt)

  // 転記するセルを指定する
  const spreadSheetApp = SpreadsheetApp
  const spreadSheet = spreadSheetApp.openById('スプレッドシートIDが入ります')
  const sheet = spreadSheet.getSheetByName('請求額')
  const row = sheet.getLastRow() + 1
  const dateRange = sheet.getRange(row, 1) // 日付を記入するセルを指定
  const notIncludedRange = sheet.getRange(row, 2) // 税抜請求額を記入するセルを指定
  const includedRange = sheet.getRange(row, 3) // 税込請求額を記入するセルを指定

  // 日付を記入する
  dateRange.setValue(date)

  // 税抜請求額を記入する
  notIncludedRange.setValue(taxNotIncludedInt)

  // 税込請求額を記入する
  includedRange.setValue(taxIncludedInt)

}


つくったinsertBillingAccount関数を、searchGmail関数から呼び出してあげます。

const searchGmail = () => {
  // 中略
  
  // 通知用のメッセージをつくる ※位置を上から移動
  const chatMessage = `${companyName}の${invoiceDate}請求書が届きました。\n${taxNotIncluded} ${taxIncluded}\n以下のURLからダウンロードしてください。\n${invoiceUrl}`
  
  // 不要なGoogleドキュメントファイルを削除する
  const removingFile = drive.getFileById(document.id)
  removingFile.setTrashed(true)

  sendChatwork(chatMessage)
  sendSlack(chatMessage)

  // スプレッドシートに転記する
  insertBillingAcount(invoiceDate, taxNotIncluded, taxIncluded)
}


実行結果


このようにスプレッドシートにデータが書き込まれてます。(slackとchatworkにもメッセージが投稿されました)

翌月以降は次の行に書き込まれていきますので、これで転記する必要はなくなります。


最後にもうひと仕上げ。

処理した請求書メールを既読にしておかないとメールの内容を読みにいってしまいます。

また、請求書メールが届いていなかったりするとプログラムがエラーで終了してしまいます。

次回はそれらを解決し、安心の自動化を実現します。


アンニョン

Copied title and URL