Google Apps Script(GAS)を使うと、請求書の自動作成が可能です。
さらに作成した請求書をPDFとしてGoogleドライブに保管するところまで自動化できます。
この記事では請求書作成を自動化するプログラムを紹介していきます。
・作成した請求書をPDF化
・所定のフォルダにPDFを保管
Google Apps Scriptでの仕組み作りは無料です。
もし請求書作成を自動化したい人は、GASプログラムを参考にしてみてください。
目次
GASで請求書作成を自動化する方法を解説
使用手順2|スプレッドシートのデータ確認
使用手順3|GASプログラムを実行
使用手順4|ライブラリ設定
使用手順5|確認作業
以下で詳しく説明していきます。
使用手順1|請求書フォーマットを作成
今回は以下のような請求書フォーマットを作成してみました。
上記のうち、1~7は自動で入力される項目(可変情報)で、8~15は事前に入力しておく項目(固定情報)です。
1|取引先
2|請求書の件名
3|合計金額(請求金額)
4|支払い期限
5|請求の詳細項目
6|請求書ID
7|請求日
8|請求側の企業名
9|請求側の企業住所
10|請求側の企業の電話番号
11|請求側の企業の担当者
12|支払先の銀行口座
13|請求書PDFの保管先(Google Drive)
14|請求項目の開始日
15|請求項目の終了日
8~15については以下の情報を事前に入力しておきます。
事前入力項目8~12|会社情報
9|請求側の企業住所
10|請求側の企業の電話番号
11|請求側の企業の担当者
12|支払先の銀行口座
上記の5つの情報は会社の情報なので、事前に入力しておきます。
事前入力項目13~15|請求書作成の情報
14|請求項目の開始日
15|請求項目の終了日
上記の3つは今回の請求書自動作成GASプログラムに必要な情報なので、事前に入力しておく必要があります。
たとえば、以下のような内容を入力しておきます。
・請求書PDFを保管したいGoogleドライブのURLを入力
・シート1の納品日の内、「14|請求項目の開始日」~「15|請求項目の終了日」に含まれる行のみを請求書に反映
・期間開始と期間終了を変更することで、より柔軟に請求書を作成できる(月末締め、15日締めなどのパターンに対応可能)
使用手順2|スプレッドシートのデータ確認
今回扱う事例は以下です。
B列|摘要
C列|納品日
D列|取引金額
E列|取引先
上の画像で表示している「シート1」のデータを「使用手順1で紹介した請求書フォーマット」に流し込み、PDFとして保存します。
この一連の作業をGASプログラムで自動化します。
使用手順3|GASプログラムをコピペ
以下の手順でプログラムを実行していきます。
2. 「スクリプトエディタ」をクリック
3. GASプログラムをデフォルトの記載を削除
4. この記事で紹介しているGASプログラムをコピペ
5. ファイルをクリック
6. 保存をクリック
以下で一つずつ解説していきます。
以下の画像は、別の記事を転用しているものがあります。
操作の内容に違いがないため、画像を修正せずにそのまま使用しています。
ご了承ください。
そうすると、以下のスクリプトエディタを出現します。
ちなみに1と2の作業は以下のショートカットキーでも開くことが可能です。
1. ツールをクリックする|[Alt] + [T]
2. スクリプトエディタをクリックする|[E]
以下のリンク先のGASプログラムをコピーします。(リンク先は同じページ下部です)
まず、以下のスクリプトエディタを選択して、もともと記載されているプログラムを削除します。
そして、コピーしたGASプログラムソースを貼り付けます。
ここまで作業が進むと以下のようになっているはずです。
ここまで出来たら、以下のとおりファイルを保存します。
5と6の作業は、[Ctrl] + [S]のショートカットキーを使うことをオススメ
プログラミングだけでなく、パソコン仕事においてはショートカットキーを使う方が早いです。
ぜひショートカットキーでの作業をオススメします。
7の作業は、[Ctrl] + [R]のショートカットキーを使うことをオススメ
ちなみにプログラムエディタの背景色が黒にする方法や、正確な操作を知りたい人がいるかもしれません。
その場合は、以下の動画をご覧いただくことをオススメします。
上記の動画では、GASを使い始めるまでの操作手順を動画で解説しています。
もし動画よりテキストのほうが得意な人は、以下の記事を参考にしていただくと良いです。
作成手順4|ライブラリ設定
続けて、ライブラリ設定をします。
この記事で紹介するプログラムでは、「Momemnt.js」というライブラリを使用します。
ライブラリとは簡単に言うと、特定の機能を引用する方法です。
「Moment.js」というライブラリを使うと、日付の比較がとてもラクになります。
今回は、2020/07/01~2020/07/31のデータのみを請求書に反映したいので、その日付比較でMoment.jsを使っています。
ただ、ライブラリは使用するために設定が必要です。
以下、その設定方法を紹介します。
2. 「ライブラリ」をクリック
3. Momentのライブラリキーをコピぺ
4. 「追加」をクリック
5. バージョンは「9」を選択(9以上があれば、番号が大きいものを選択)
6. 「保存」をクリック
以下のライブラリキーをコピーします。
MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48
コピーしたライブラリキーを以下のように貼り付けます。
これでMoment.jsライブラリを使用できるようになります。
なお、このライブラリ設定を行わないとプログラムが動かないので、注意が必要です。
使用手順5|確認作業
プログラムを実行すると、以下のようになります。
・取引先ごとにシートを作成(取引先が増えても自動処理される)
・取引先ごとのシートをPDFとして所定のフォルダに保存
・この事例では2020/07/01~2020/07/31の期間の取引のみを抽出
・PDF化するシート範囲は必要な部分のみに限定
・PDFの名前は取引先の名称(プログラムで変更可能)
ちなみに自動で作成されるシートは以下のようになります。
プログラムの解説は記事後半で行っています。
GASで請求書を自動作成|PDF化を解説
GASで請求書の自動作成してPDFを作成するプログラムは以下です。
今回使用しているGASプログラムを以下に記載しているので、コピペして活用ください。
・もし、このプログラムを仕事で使いたい場合は、ご自身が取り扱うデータに合わせて変更が必要になります
・プログラムの中に、できるだけコメントを入れておいたので、そのコメントを参考にしていただければと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
//プログラムA-0|プログラム名 function Seikyusho() { //プログラムA-1|スプレッドシートを設定 var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();//変数spreadsheetに「アクティブなスプレッドシート」を設定 var sheet = spreadsheet.getSheetByName('シート1');//変数sheetに「シート1」シートを設定 var myRange = sheet.getDataRange().getValues();//スプレッドシートのデータを二次元配列として取得 //プログラムA-2|変数templateに「請求書フォーマット」シートを設定 var template = spreadsheet.getSheetByName('請求書フォーマット');//変数sheetに「請求書フォーマット」シートを設定 var start= template.getRange('J4').getValue();//「請求書フォーマット」のセルJ4の日付を取得 var startdate = Moment.moment(start).subtract(1, 'd');//変数startの日付をMomentで設定(1日前を設定) var end= template.getRange('J5').getValue();//「請求書フォーマット」のセルJ5の日付を取得 var enddate = Moment.moment(end).add(1, 'd');//変数endの日付をMomentで設定(1日後を設定) //プログラムA-3|空の配列を設定 var torihiki = []; //プログラムA-4|プログラム2の取引先(E列)をプログラム3の空配列に取得 for (var i=1; i<myRange.length; i++){ torihiki.push(myRange[i][4]);//配列torihikiにmyRange[i][4]を追加 } //プログラムA-5|プログラム4の取引先名の重複を削除 var torihiki_list = torihiki.filter(function(value, i, self){ return self.indexOf(value) === i; }); //プログラムA-6|商品名ごとに繰り返す for (var i=0; i<torihiki_list.length; i++){ //プログラムA-6-1|空の配列を設定 var myID = [];//シート1のA列「ID」格納用 var myTekiyo = [];//シート1のB列「摘要」格納用 var myNouhin = [];//シート1のC列「納品日」格納用 var myKingaku = [];//シート1のD列「取引金額」格納用 //プログラムA-6-2|取引先ごとに、プログラム6-1で設定した配列に格納 for (var k=0; k<myRange.length; k++){ if (Moment.moment(myRange[k][2]).isAfter(startdate) && Moment.moment(myRange[k][2]).isBefore(enddate)){//myRange[k][2](納品日)がstartdateより後、かつenddateより前ならば if (myRange[k][4] == torihiki_list[i]){ //myRange[k][4](取引先)とtorihiki_list[i]が一致すれば myID.push([myRange[k][0]]);//配列myIDにmyRange[k][0]を追加 myTekiyo.push([myRange[k][1]]);//配列myTekiyoにmyRange[k][1]を追加 myNouhin.push([myRange[k][2]]);//配列myNouhinにmyRange[k][2]を追加 myKingaku.push([myRange[k][3]]);//配列myKingakuにmyRange[k][3]を追加 } } } //プログラムA-6-3|シートを追加して、シート名を各取引先に変更 var newsheet = template.copyTo(spreadsheet);//「請求書フォーマット」のシートをコピーする newsheet.setName(torihiki[i]);//コピーしたシートの名前を「torihiki[i]」にする //プログラムA-6-4|ID,摘要,納品日,取引金額を新しいシートの14行目以下に貼り付け newsheet.getRange(14,2,myID.length,myID[0].length).setValues(myID);//セルB14以下に「ID」情報を貼り付け newsheet.getRange(14,3,myTekiyo.length,myTekiyo[0].length).setValues(myTekiyo);//セルC14以下に「摘要」情報を貼り付け newsheet.getRange(14,6,myNouhin.length,myNouhin[0].length).setValues(myNouhin);//セルF14以下に「納品日」情報を貼り付け newsheet.getRange(14,7,myKingaku.length,myKingaku[0].length).setValues(myKingaku);//セルG14以下に「取引金額」情報を貼り付け //プログラムA-6-5|変数goukeiを0リセット var goukei = 0; //プログラムA-6-6|14行目以降のC~Eを結合して、取引金額の合計値を算出 for (var j=0; j<myID.length; j++){ var row = j+14;//行のカウントアップ newsheet.getRange('C'+ row + ':E' + row).merge();//セルC~セルEの結合 goukei = goukei + Number(myKingaku[j]);//取引先ごとの取引金額を算出 } //プログラムA-6-7|シートに請求書情報を入力 var today = Moment.moment(new Date()); var hiduke = Moment.moment(start); var duedate = today.clone().add(15, 'd').format('YYYY/MM/DD');//請求日の期限を設定 var month = hiduke.clone().format('YYYY年MM月');//年月の取得 var formatteddate = today.clone().format('YYYY/MM/DD'); newsheet.getRange('B4').setValue(torihiki_list[i]);//請求書のセルB4に取引先を入力 newsheet.getRange('B6').setValue('下記項目のとおり請求致します');//請求書のセルB6に入力 newsheet.getRange('G3').setValue(formatteddate + '_' + Number(i+1));//請求書のセルG3に請求書IDを入力 newsheet.getRange('G4').setValue(new Date());//請求書のセルG4に請求日(今日の日付)を入力 newsheet.getRange('C9').setValue(goukei + '円');//請求書のセルC9に合計金額を入力 newsheet.getRange('C11').setValue(duedate);//請求書のセルC11に請求日の期限を入力 newsheet.getRange('B14:G' + row).setBorder(true, true, true, true, true, true);//14行目~最終行まで罫線を引く Utilities.sleep(1000); //1秒待機(待機中に情報を更新) SpreadsheetApp.flush(); //挿入したシートの情報更新 //プログラムA-6-8|PDF化 var ssId = spreadsheet.getId();//スプレッドシートIDを取得 var sheetId = newsheet.getSheetId();//取引先のシートIDを取得 var folderurl = newsheet.getRange('J2').getValue();//newsheetのセルJ2の値(PDF保管先のフォルダURL) var myArray= folderurl.split('/'); //folderurlを「/」で区切る var folderid = myArray[myArray.length-1];//変数folderidにフォルダIDを取得 var folder = DriveApp.getFolderById(folderid);//PDF保管先のfolderを設定 PDFexport(ssId, sheetId,torihiki_list[i],row, folder);//プログラムBを実行(5つの引数を渡す) } } //プログラムB-0|PDF化 function PDFexport(ssId, sheetId, torihiki, row, folder) { //プログラムB-1|PDF化の条件設定 var url = 'https://docs.google.com/spreadsheets/d/'+ ssId +'/export?'; var opts = { exportFormat: 'pdf', // ファイル形式の指定 format: 'pdf', // ファイル形式の指定 size: 'A4', // 用紙サイズの指定 portrait: 'true', // true縦向き、false 横向き fitw: 'true', // 幅を用紙に合わせるか? sheetnames: 'false', // シート名を PDF 上部に表示するか? printtitle: 'false', // スプレッドシート名をPDF上部に表示するか? pagenumbers: 'false', // ページ番号の有無 gridlines: 'false', // グリッドラインの表示有無 fzr: 'false', // 固定行の表示有無 range : 'A1%3AG' + row, // 対象範囲「%3A」 = : (コロン) gid: sheetId // シート ID を指定 (省略する場合、すべてのシートをダウンロード) }; //プログラムB-2|PDF化のurl作成 var PDFurl = [];//urlという空配列を設定 for(optName in opts){ PDFurl.push(optName + '=' + opts[optName]);//opts配列の各要素を=でつないだものをurl配列に格納 } var options = PDFurl.join('&');//urlの配列の各要素を&でつなぐ //プログラムB-3|PDF化の条件設定 var token = ScriptApp.getOAuthToken();//アクセストークンを取得 var response = UrlFetchApp.fetch(url + options, {headers: {'Authorization': 'Bearer ' + token}}); //PDFのURLからアクセスする var blob = response.getBlob().setName(torihiki + '.pdf');//PDFの名前を「取引先+.pdf」とする var newFile = folder.createFile(blob);//PDFを所定のフォルダに保管する newFile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);//共有設定をする:「リンクを知っている人」が「閲覧可能」 } |
PDF化の部分はこちらを参考にさせていただきました。
プログラムの詳細説明は省きますが、問い合わせが多ければ解説を入れていきたいと考えています。
Google Apps Script(GAS)について詳しく理解したいなら
Google Apps Script(GAS)を活用すると、仕事を効率化できる幅を広げることができます。
たとえば私が実際にGASを活用して効率化してきた作業は以下の動画で解説しています。
動画を見てみると、あなたの仕事にどのようにGASを応用すればいいのかイメージが浮かぶこともあると思います。
ぜひご覧ください。
GASの使い方・始め方を知らない人にはこちらの記事・動画がオススメ
この機会に、「GASを使い方を知りたい」と思った人もいるかもしれません。
そのように感じている人は、ぜひ以下の記事をご覧ください。
10分程度でGoogle Apps Scriptを使うためのスタート地点に立てるように解説をしています。
GASで出来ることを知らない人はこちらの記事・動画がオススメ
GASの始め方を理解する前に、やっておくことがあります。
それは、GASを使って何ができるのかを理解しておくことです。
なぜならGASの使い所を知らないと、仕事で使えないからです。
仕事でどう活用するかをイメージしないまま学んでも、効果的な学習ができません。
そこで、このサイトでもいくつか事例を使って、GASの実践方法を紹介しています。
興味がある人は以下の記事もご覧ください。
オススメの書籍を紹介
書籍に関しては、以下を読んで購入しました。
GASの全体感をつかむには良いと思います。
ただし、実際の勉強は書籍よりもウェブサイトを活用してきました。
はっきり言って、ウェブサイトだけでも十分に勉強できるほど数多くの情報がアップされています。
書籍で全体感をつかんだら、ウェブサイトでの学習に切り替えたほうが良いのが私の考えです。
Googleスプレッドシートを効率的に操作したいなら
この記事ではGASを活用した仕事の効率化の事例を紹介してきました。
しかしGoogleスプレッドシートの仕事を早くすることを目指すなら、GAS以外の方法もあります。
たとえば、以下の方法です。
上記の内容については、以下の動画で紹介しています。
ぜひGoogleスプレッドシートを上手に扱えるようになりたい人はご覧いただきたいです。