GASの効率化講座の最後のお勉強は、スプレッドシートの内容から請求書PDFを作成してメールで送るという内容です。
一通り終わりましたが、正直なところ高階関数(関数の中に関数を入れる)が難しくて、理解度は30%ほどです。
私が受講したUdemyの講座
「Google Apps Scriptの仕事効率化・自動化をプログラミングで実現」という講座のセクション11:[自動化⑥]複数の請求書を自動発行の内容です。
この講座をすべて終えるまで、約14時間かかりました。
なかなか骨がありますね。
今回学んだ内容
請求書なんて発行したことないですが。
スプレッドシートの内容を元に、請求書PDFを作って送付する処理です。
1行につき1つのPDFを作って送るだけならば、それほど難しくないのですが、1つの会社で複数の注文があった場合に1つの請求書PDFにまとめる部分が肝です。この部分を、高階関数を使って配列情報をグループ化して扱うところが難しかったです。
関数の中に関数を入れる高階関数
reduce関数というものを今回は使いました。
これにより配列を別の配列にグループ化してまとめるという使い方ができます。
正直、言葉で説明するのは難しいので図で示すと以下のような感じです。
何となく分かりますかね。
スプレッドシートをPDFに変える
スプレッドシートをPDFに変えるには、実はURLを少し変更してブラウザから実行すればOKです。
ブラウザからの実行ならばこれでOKですが、GASから実行する際にはUrlFetchAppクラスを使ってPDFを作成します。これはお作法的な部分があるので、チュートリアルなどを見ればOKだと思います。
実際に書いたコード、実行結果
実際に書いたコードを記録しておきます。
今は使う予定はありませんが、いつか応用できるはずなので。
実際に書いたコード
reduce関数、やばい、むずかしか。
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var invoiceItemSheet = ss.getSheetByName("請求品目リスト");
var lastRow = invoiceItemSheet.getLastRow();
console.log(lastRow);
var beforeArray = invoiceItemSheet.getRange(`A2:H${lastRow}`).getValues();
var hinagata = ss.getSheetByName("ひながた");
//スプレッドシートのデータを配列として取得
var tmpArr = [];
for(var i = 0; i < beforeArray.length; i++){
var obj ={};
for(var j = 0; j < beforeArray[i].length; j++){
obj["companyName"] = beforeArray[i][1];
obj["title"] = beforeArray[i][2];
obj["invoiceItemName"] = beforeArray[i][3];
obj["number"] = beforeArray[i][4];
obj["unitName"] = beforeArray[i][5];
obj["price"] = beforeArray[i][6];
}
tmpArr.push(obj);
}
//請求書に記載するデータを配列として取得 ※reduce関数でグループ分けして取得
var resultArr = tmpArr.reduce(function(acc,objItem){
//データの存在確認用 ※既に請求書発行する会社が存在すればそのインデックス番号を返す
var i = acc.findIndex(function(data){
return data.companyName == objItem.companyName;
});
//データ整形して返す
var arr = [objItem.invoiceItemName,"","",objItem.number,objItem.unitName,objItem.price];
if(i < 0){
acc.push({
companyName:objItem.companyName,
title:objItem.title,
arrays:[arr]
});
}else{
acc[i].arrays.push(arr);
}
return acc;
},[]);
for(var i = 0; i < resultArr.length; i++){
//新しいスプレッドシートを作成し請求書とする
var newSheet = hinagata.copyTo(ss);
newSheet.getRange(`A17:F${16 + resultArr[i].arrays.length}`).setValues(resultArr[i].arrays);
newSheet.getRange("A3").setValue(resultArr[i].companyName);
newSheet.getRange("B7").setValue(resultArr[i].title);
newSheet.setName(resultArr[i].companyName);
SpreadsheetApp.flush();
//PDFを作る
var gid = newSheet.getSheetId();
var token = ScriptApp.getOAuthToken();
var ssid = "1XD09ctF695aNMKQaM8H8FH1FiAhtcfBfIMzoQqg7xxx";
var printRange = encodeURIComponent("A1:G37");
var opts = {
format:"pdf",
gid:gid,
size:"A4",
portrait:"true",
fitw:"true",
sheetnames:"false",
printname:"false",
pagenumber:"false",
gridlines:"false",
fzr:"false",
range:printRange
}
var optUrl = [];
for(optName in opts){
optUrl.push(optName + "=" + opts[optName]);
}
var options = optUrl.join("&");
var url = "https://docs.google.com/spreadsheets/d/"+ ssid + "/export?"
var pdf = UrlFetchApp.fetch(url + options, {
headers:{
"Authorization":"Bearer " + token
}
}).getBlob().setName(resultArr[i].companyName + "様 請求書.pdf");
var to = "xxx@mosomoso-history.com";
var subject = "請求書です";
var body = "ご確認のほど、よろしくお願い申す。";
//メールを送る
GmailApp.sendEmail(to, subject, body, {
attachments:pdf
});
}
}
実行結果
1.ひながたシートから、別のシートができます。
2.このシートがPDFになって、メールが送られます。
少し違和感を覚えたけど些細な事
今回書いたコードだと、請求書送信先のメールアドレスはベタ打ちです。
実務で使うには、請求先のメールアドレスを別のシートから取得するようなコードが必要でしょうね。
今回学んだreduce関数に比べれば、難しく無さそうなため些細なことだというわけです。
まとめ
1.関数の中に関数を入れる高階関数について学びました。
ただ理解度は30%程度、本格的に使う際に要復習だと思います。やったことがあるというのがいつか大きな財産になる、という山王精神でいきましょう。
2.スプレッドシートをPDFにする方法を学びました。
3.Excelの代わりにスプレッドシートをよく使うようになってきたので、本講座で学んだ内容は今後も発展させて使っていきたいと思います。
コメント