2020年9月26日土曜日

Gmailで定期的にメールを自動送信する。

通常の機能だと(たぶん)できないGmailでの定期的な自動送信。でも、GAS(Google Apps Script)を使うと簡単にできます。

さわでは直売所の売り上げ確認のために毎日空メールを送る必要があるのですが、こういう場合に便利です。


① コードの作成

「Google ドライブ」の「新規」→「その他」→「Google Apps Script」よりスクリプトファイルを作成します。コードは以下の通り。

function myFunction() {
  GmailApp.sendEmail(
    '送信先メールアドレス', 
    '件名',
    '本文'
  );
}

空メールですと「件名」「本文」はシングルコーテーション「'」で囲う形になります。


function myFunction() {
  GmailApp.sendEmail(
    '送信先メールアドレス', 
    '件名',
    '本文',
    {
      from: '送信元メールアドレス',
      name: '送信者名'
    }
  );
}

オプションでfrom(送信元メールアドレス)、name(送信者名)、cc、bccなども指定できます(詳しくはこちら参照)。

送信元メールアドレスにはGmail アカウントにエイリアスとして追加している別アドレスも指定できます(参考:Gmail の「エイリアスとして扱います」の使用方法)。


詳解! Google Apps Script完全入門 [第3版]
詳解! Google Apps Script完全入門 [第3版]

by SimpleImageLink


② トリガーの設定

定期的にメールを送信するためにトリガーの設定をします。

以下、例です。

「トリガーを追加」より、

・「実行する関数を選択」→ myFunction
・「実行するデプロイを選択」→ Head
・「イベントのソースを選択」→ 時間主導型
・「時間ベースのトリガーのタイプを選択」→ 日付ベースのタイマー
・「時刻を選択」→ 午前7時〜8時
・「エラー通知設定」→ 毎日通知を受け取る

適宜設定してください。


***

このメール送信のスクリプトを以前作成した「予定通知LINE bot」と組み合わせれば通知をメールで送ることもできますね。

定期業務は自動化できると時間のゆとりも作れます。うまく使っていきたいですね。




Twitter(@nkkmd)、Instagram(@nkkmd)も日々更新中です。

2020年9月23日水曜日

減価償却費の計算用スプレッドシート(定額法・平成19年4月1日以後取得の資産に対応)

減価償却費の計算用スプレッドシートを作ってみました。計算と減価償却資産ごとのシートの作成はGAS(Google Apps Script)で自動化しています。手作業で計算するととても面倒ですからね。

平成19年4月1日以後に取得した減価償却資産を定額法を用いて計算する場合に使うことができます。

スプレッドシートやエクセルでは減価償却費の計算(定額法)をするSLN関数が用意されていますが、これはそのまま使うとずれるのですね。なので、計算式は自分で作る必要があります。


① スプレッドシートのダウンロード




PCでGoogleアカウントにログインした状態で、リンク先にて「ファイル」から「コピーを作成」で編集可能なファイルが作成されます。エクセルで使いたい方はファイル作成後にMicrosoft Excel(.xlsx)形式でダウンロードすれば使えると思います。

(時々、アクセス権のリクエストをいただきますが、こちらの方法で編集可能なコピーを作成してご使用ください。)

スプレッドシートには「参照」「減価償却費データ」「減価償却資産リスト」「1サンプル」というシートが含まれています。

次にGASのコードの作成を行います。


② コードの作成

スプレッドシートの「ツール」→「スクリプト エディタ」からスクリプトファイルを作成します。コードは以下の通りです。

function depreciableAssets() {
  var spreadsheet = SpreadsheetApp.getActive();
  var sheet = spreadsheet.getSheetByName("減価償却資産リスト");
  var lastRow = sheet.getLastRow();
  
  var num = sheet.getRange(lastRow, 1).getValue(); //管理番号 
  var name = sheet.getRange(lastRow, 2).getValue(); //資産名称
  var acc = sheet.getRange(lastRow, 3).getValue(); //勘定科目
  var date = sheet.getRange(lastRow, 4).getValue(); //取得年月日  
  var year = Utilities.formatDate(date, "JST", "yyyy"); //取得年
  var month = Utilities.formatDate(date, "JST", "MM"); //取得月
  var life = sheet.getRange(lastRow, 5).getValue(); //耐用年数
  var ratio = sheet.getRange(lastRow, 6).getValue(); //事業専用割合
  var qty = sheet.getRange(lastRow, 7).getValue(); //数量
  var price = sheet.getRange(lastRow, 8).getValue(); //単価
  
  var depreciation = qty * price; //取得価格(償却費)
  var rate = "=VLOOKUP(E" + lastRow + ",'参照'!$A$2:$B$100,2,FALSE)"; //償却率
  var expense = depreciation * ratio; //経費算入額
  var months = 13 - month; //初年償却月数
  
  sheet.getRange(lastRow, 9).setValue(depreciation);
  sheet.getRange(lastRow, 10).setValue(rate);
  sheet.getRange(lastRow, 11).setValue(expense);
  sheet.getRange(lastRow, 12).setValue(months);
  
  rate = sheet.getRange(lastRow, 10).getValue();
    
  spreadsheet.insertSheet(num + name);
  var newSheet = spreadsheet.getSheetByName(num + name);

  newSheet.getRange(1, 1).setValue("管理番号");
  newSheet.getRange(1, 1).setBackground("#d9ead3");
  newSheet.getRange(1, 2).setValue(num);
  newSheet.getRange(1, 1, 1, 2).setBorder(true, true, true, true, true, false);
  
  newSheet.getRange(3, 1).setValue("資産名称");
  newSheet.getRange(3, 1).setBackground("#d9ead3");
  newSheet.getRange(3, 2).setValue(name);
  newSheet.getRange(4, 1).setValue("勘定科目");
  newSheet.getRange(4, 1).setBackground("#d9ead3");
  newSheet.getRange(4, 2).setValue(acc);
  newSheet.getRange(3, 3).setValue("取得年月日");
  newSheet.getRange(3, 3).setBackground("#d9ead3");
  newSheet.getRange(3, 4).setValue(date);
  newSheet.getRange(4, 3).setValue("耐用年数");
  newSheet.getRange(4, 3).setBackground("#d9ead3");
  newSheet.getRange(4, 4).setValue(life);
  newSheet.getRange(3, 5).setValue("事業専用割合");
  newSheet.getRange(3, 5).setBackground("#d9ead3");
  newSheet.getRange(3, 6).setValue(ratio);
  newSheet.getRange(3, 6).setNumberFormat("0%");
  newSheet.getRange(4, 5).setValue("償却率");
  newSheet.getRange(4, 5).setBackground("#d9ead3");
  newSheet.getRange(4, 6).setValue(rate);
  newSheet.getRange(4, 6).setNumberFormat("0.000");
  newSheet.getRange(3, 1, 2, 6).setBorder(true, true, true, true, true, true);

  newSheet.getRange(6, 1).setValue("経過年数");
  newSheet.getRange(7, 1).setValue("1");
  newSheet.getRange(6, 2).setValue("対象年");
  newSheet.getRange(7, 2).setValue(year);
  newSheet.getRange(6, 3).setValue("数量");
  newSheet.getRange(7, 3).setValue(qty);
  newSheet.getRange(6, 4).setValue("単価");
  newSheet.getRange(7, 4).setValue(price);
  newSheet.getRange(7, 4).setNumberFormat("[$¥-411]#,##0");
  newSheet.getRange(6, 5).setValue('="取得価格"&CHAR(10)&"(償却費)"');
  newSheet.getRange(7, 5).setValue(depreciation);
  newSheet.getRange(7, 5).setNumberFormat("[$¥-411]#,##0");
  newSheet.getRange(6, 6).setValue("経費算入額");
  newSheet.getRange(7, 6).setValue(expense);
  newSheet.getRange(7, 6).setNumberFormat("[$¥-411]#,##0");
  newSheet.getRange(6, 7).setValue("初年償却月数");
  newSheet.getRange(7, 7).setValue(months);
  newSheet.getRange(6, 8).setValue('="対象年"&CHAR(10)&"経費算入額"');
  newSheet.getRange(7, 8).setValue("=ROUND((F7*F4)*G7/12,0)");
  newSheet.getRange(7, 8).setNumberFormat("[$¥-411]#,##0");
  newSheet.getRange(6, 9).setValue('="対象年末"&CHAR(10)&"未償却残高"');
  newSheet.getRange(7, 9).setValue("=F7-H7");
  newSheet.getRange(7, 9).setNumberFormat("[$¥-411]#,##0");
  newSheet.getRange(6, 10).setValue("備考");   
  for(var i = 1; i < 11; i++){
    newSheet.getRange(6, i).setBackground("#d9ead3");
    newSheet.getRange(6, i).setHorizontalAlignment("center");
  }
  newSheet.getRange(6, 1, 1, 10).setBorder(true, true, true, true, true, false);

  newSheet.getRange(8, 1).setValue("=$A7+1"); //経過年数
  newSheet.getRange(8, 2).setValue("=$B7+1"); //対象年
  newSheet.getRange(8, 8).setValue("=ROUND(IF((I7-(F7*F4))<=0,(((F7*F4)+(I7-(F7*F4))))-1,(F7*F4)),0)"); //対象年経費算入額
  newSheet.getRange(8, 8).setNumberFormat("[$¥-411]#,##0");
  newSheet.getRange(8, 9).setValue("=IF((I7-H8)<=0, 1,(I7-H8))"); //対象年末未償却残高
  newSheet.getRange(8, 9).setNumberFormat("[$¥-411]#,##0");
  newSheet.getRange(7, 1, 1, 10).setBorder(true, true, false, true, true, false);

  life = life + 1;
  
  var row1 = 8;
  var row2 = 7;

  for(var j = 1; j < life; j++){
    newSheet.getRange(row1, 1).setValue("=A" + row2 + "+1"); //経過年数
    newSheet.getRange(row1, 2).setValue("=B" + row2 + "+1"); //対象年
    newSheet.getRange(row1, 8).setValue("=ROUND(IF((I" + row2 + "-(F7*F4))<=0,(((F7*F4)+(I" + row2 + "-(F7*F4))))-1,(F7*F4)),0)"); //対象年経費算入額
    newSheet.getRange(row1, 8).setNumberFormat("[$¥-411]#,##0");
    newSheet.getRange(row1, 9).setValue("=IF((I" + row2 + "-H" + row1 + ")<=0, 1,(I" + row2 + "-H" + row1 + "))"); //対象年末未償却残高
    newSheet.getRange(row1, 9).setNumberFormat("[$¥-411]#,##0");
    newSheet.getRange(row1, 1, 1, 10).setBorder(true, true, true, true, true, false);
    newSheet.getRange(row1, 1, 1, 10).setBorder(true, null, null, null, null, null, "#000000", SpreadsheetApp.BorderStyle.DOTTED);
    
    if(newSheet.getRange(row1, 9).getValue() == 1){
      break;
    }
    
    row1 = row1 + 1;
    row2 = row2 + 1;
  }
  
  newSheet.protect().setWarningOnly(true); //シートの保護
  
  sheet.getRange(lastRow, 13).setValue('=IFERROR(VLOOKUP(YEAR(NOW())-1, INDIRECT(TEXTJOIN("", TRUE,A' + lastRow + ',B' + lastRow + ')&"!$B:$H"), 7,FALSE), 0)');
  sheet.getRange(lastRow, 14).setValue('=IFERROR(VLOOKUP(YEAR(NOW())-1, INDIRECT(TEXTJOIN("", TRUE,A' + lastRow + ',B' + lastRow + ')&"!$B:$I"), 8,FALSE), 1)');
  sheet.getRange(lastRow, 15).setValue('=IFERROR(VLOOKUP(YEAR(NOW()), INDIRECT(TEXTJOIN("", TRUE,A' + lastRow + ',B' + lastRow + ')&"!$B:$H"), 7,FALSE), 0)');
  sheet.getRange(lastRow, 16).setValue('=IFERROR(VLOOKUP(YEAR(NOW()), INDIRECT(TEXTJOIN("", TRUE,A' + lastRow + ',B' + lastRow + ')&"!$B:$I"), 8,FALSE), 1)');

}

まるっとコピペで使えるかと思います。

GASの初回実行時に承認が必要となります。無料のGoogleアカウントの場合「このアプリは確認されていません」というページが表示されます。ここで「安全なページに戻る」をクリックすると実行できませんので、「詳細」→「プロジェクト名(安全ではないページ)に移動」から承認します。


(もう少しさっぱりしたコードにできないものかと思いつつ、まぁとりあえず動けばいいでしょう。笑)


③ スプレッドシートの使い方

・「参照」シート

他シートからの参照用に定額法の償却率と勘定科目が入っています。はじめにD2:D11の範囲に必要となる勘定科目を入力してください(必要ないものは消してください)。


・「減価償却費データ」シート

自動で勘定科目ごとの資産数、償却費、経費算入額、前年経費算入額、前年末未償却残高、当年経費算入額、当年末未償却残高が表示されます。入力はありません。


・「減価償却資産リスト」シート

管理番号、資産名称、勘定科目、取得年月日、耐用年数、事業専用割合、数量、単価の8項目の入力をします(黄色のセル)。数字は全て半角です。勘定科目は「参照」シートに記載した科目をプルダウン リストから選択します。

8項目入力後、先ほど作成したGASのdepreciableAssets関数を実行します。「減価償却資産リスト」シートの取得価格(償却費)、償却率、経費算入額、初年償却月数、前年経費算入額、前年末未償却残高、当年経費算入額、当年末未償却残高が入力され、管理番号と資産名称をくっつけた名前で個別のシートが作成されます。「1サンプル」シートが例になります。

個別のシートでは耐用年数に応じて残存価格1円になるまでの対象年経費算入額と対象年末未償却残高が表示されます。



④ 注意点

depreciableAssets関数は新しい減価償却資産の入力毎に実行してください。複数資産をまとめて実行することはできません。

管理番号は重複しないように気をつけてください。

減価償却資産を除去する場合には、個別のシートと「減価償却資産リスト」シートの対象の行を削除してください。

自分でも使っていますので計算ミス等は無いように注意して作っていますが、実際にお使いになる際にはご自身でよくご確認ください。


***

自営業にとって毎年の確定申告は経営状態を把握する良い機会ですからね。正確に、かつできる限り省力化していきたいところです。

今年は領収証等も都度フォームで入力→自動で合計残高試算表作成という形にしたので、年明けとともに申告の準備が整う予定です。

(そううまくいくだろうか。笑)


2020年9月14日月曜日

ちょっと時短になる請求書と納品書と見積書のテンプレート(スプレッドシート・エクセル)

-----
・追記(2022-6-18)

-----

普段使っている請求書と納品書と見積書のスプレッドシートをテンプレートにしてみました。

請求書とか納品書とか見積書、毎回手書きや手入力しているとまぁまぁ時間かかるのですよね。そんなわけで、時短を意識して作ってあります。バックオフィス業務はただひたすらに効率化あるのみです。

GAS(Google Apps Script)で、保存用PDFの作成とナンバリングカウントの自動化もしています。必要があればお使いください。


請求書と納品書と見積書のテンプレート

・追記(2022-6-22)
新たに請求書等の発行システムを作成しました。今後はそちら(無料かつ時短になる請求書等の発行システム(電子取引の保存要件に対応)
)をお使いください。

・追記(2020-12-1)
時々、アクセス権のリクエストをいただきますが、↓の方法で編集可能なコピーを作成してご使用ください。

PCでGoogleアカウントにログインした状態で、リンク先にて「ファイル」から「コピーを作成」で編集可能なファイルが作成されます。エクセルで使いたい方はファイル作成後にMicrosoft Excel(.xlsx)形式でダウンロードすれば使えると思います。


① テンプレートの使い方

「請求書」「納品書」「見積書」「参照」「取引先」の5つのシートがあります。

「参照」と「取引先」シートは請求書、納品書、見積書内の「宛先」「日付」「振込先」「請求書番号」「納品書番号」「見積書番号」の参照用です。あらかじめ入力しておけば以降はプルダウン リストからの選択が可能になります。日付は今日を起点に前後3日間が表示されるようになっています。

「請求書番号」「納品書番号」「見積書番号」の管理は手動でも可能ですが、後ほどGASで自動化します。

ナンバリングは「20-001」のように西暦下2桁-通し番号3桁となっています。もし取引先番号等を付けたい場合には、取引先に番号をふり、VLOOKUP関数で持ってくればよいかと思います。



都度手入力となるのは「品名」「数量」「単価(税込)」(必要があれば「振込期日」「備考欄」)です。その他はプルダウン リストから選択、もしくは自動計算されます。


納品書、見積書も使い方は同じになります。


② GASでさらに時短 - その1「スプレッドシートのPDF化」

さらなる時短のためGASで請求書、納品書、見積書のPDF化とナンバリングのカウントを自動化します。

発行した請求書、納品書、見積書はPDFファイルとして保存しているのですが、このスプレッドシートからのPDF化が微妙に手間がかかるのですよね。なんやかんや30秒程度でしょうか。Google ドライブ内で保存できればいい場合でも一旦ローカルにファイルが作成されてしまいますし、ファイル名も規則通りに間違えないよう打ち込まねばなりません。ルール通りにやればいいことはプログラムにやってもらった方が早いし間違いがないですね(予期せぬエラーはありますが)。

ということで、まずはPDF化のコードです。

function pdfInv(){
    var folderId = "フォルダーID";
    var spshId = "スプレッドシートID";
    var shtId = "シートID";
    var actSpsh = SpreadsheetApp.getActiveSpreadsheet();
    var sht = actSpsh.getSheetByName("請求書");
    var clName = sht.getRange("A3").getValue();
    var num = sht.getRange("F5").getValue();
    var dateStamp = sht.getRange("F4").getValue();
    var dateStamp = Utilities.formatDate(dateStamp, "JST", "yyyy-MM-dd");
  
    createPDF( folderId, spshId, shtId, "請求書" + "_" + clName + "_" + num + "(" + dateStamp + ")" );
}

function createPDF(folderId, spshId, shtId, fileName){
    var folder = DriveApp.getFolderById(folderId);
    var url = "https://docs.google.com/spreadsheets/d/spshId/export?".replace("spshId", spshId);

    var opts = {
      exportFormat: "pdf",
      format:       "pdf",
      size:         "A4",
      portrait:     "true",
      fitw:         "true",
      sheetnames:   "false",
      printtitle:   "false",
      pagenumbers:  "false",
      gridlines:    "false",
      fzr:          "false",
      gid:          shtId
    };
  
    var url_ext = [];
    for( optName in opts ){
      url_ext.push( optName + "=" + opts[optName] );
    }
    var options = url_ext.join("&");
    var token = ScriptApp.getOAuthToken();
    var response = UrlFetchApp.fetch(url + options, {
      headers: {
        'Authorization': 'Bearer ' +  token
      }
    });
    var blob = response.getBlob().setName(fileName + '.pdf');

    folder.createFile(blob);
}

上記は請求書のPDF化のコードになります。納品書、見積書はまた別にコードを作成する必要があります。

書き換え箇所は以下の通りです。

・1行目「pdfInv」

納品書の場合は「pdfDn」、見積書の場合は「pdfQuot」等、それぞれ関数名を異なるものにしてください。


・2行目「フォルダーID」

PDF化したファイルを保存しておくフォルダになります。フォルダーを開いた状態でURLの下記部分に表示されます。

https://drive.google.com/drive/folders/ここの値をコピペ


・3行目「スプレッドシートID」

スプレッドシートを開いた状態でURLの下記部分に表示されます。

https://docs.google.com/spreadsheets/d/ここの値をコピペ/edit#gid=0


・4行目「シートID」

シートを開いた状態でURLの下記部分に表示されます。

https://docs.google.com/spreadsheets/d/**********/edit#gid=ここの数字をコピペ


・6、12行目「請求書」

納品書、見積書の場合はそれぞれ変更してください。


これでPDF化のコードは完成です。

ファイル名は、

書類名_宛名_書類番号(日付).pdf

という形式になります。(日付が空欄の場合はエラーになります。)


③ GASでさらに時短 - その2「ナンバリングのカウント」

次に請求書番号、納品書番号、見積書番号のナンバリングのカウントです。更新日とともに管理することで間違い防止も兼ねています。

以下コードです。

var spsh = SpreadsheetApp.openById("スプレッドシートID");
var sht = spsh.getSheetByName("参照");

var today = new Date();
var year = Utilities.formatDate(today,"JST","yyyy");
var date = Utilities.formatDate(today,"JST","yyyy/MM/dd");

function countInv() {
    var count = sht.getRange(6,2).getValue();
    count = count + 1;
    var upd = sht.getRange(6,4).getValue();
    var updYear = Utilities.formatDate(upd,"JST","yyyy");
    
    if(year == updYear){
      sht.getRange(6,2).setValue(count);
      sht.getRange(6,4).setValue(date);
    } else {
      sht.getRange(6,2).setValue("1");
      sht.getRange(6,4).setValue(date);      
    }
}

function countDn() {    
    var count = sht.getRange(7,2).getValue();
    count = count + 1;
    var upd = sht.getRange(7,4).getValue();
    var updYear = Utilities.formatDate(upd,"JST","yyyy");
    
    if(year == updYear){
      sht.getRange(7,2).setValue(count);
      sht.getRange(7,4).setValue(date);
    } else {
      sht.getRange(7,2).setValue("1");
      sht.getRange(7,4).setValue(date);    
    }
}

function countQuot() {
    var count = sht.getRange(8,2).getValue();
    count = count + 1;
    var upd = sht.getRange(8,4).getValue();
    var updYear = Utilities.formatDate(upd,"JST","yyyy");
    
    if(year == updYear){
      sht.getRange(8,2).setValue(count);
      sht.getRange(8,4).setValue(date);
    } else {
      sht.getRange(8,2).setValue("1");
      sht.getRange(8,4).setValue(date);    
    }
}

書き換えは1行目の「スプレッドシートID」のみです。PDF化のコードのスプレッドシートIDと同一のものになります。

「countInv」が請求書番号、「countDn」が納品書番号、「countQuot」が見積書番号のカウントをする関数になります。

年の切り替わりで番号はリセットされるようになっています。


***

適宜カスタマイズして使っていただければと思います。


詳解! Google Apps Script完全入門 [第3版]
詳解! Google Apps Script完全入門 [第3版]

by SimpleImageLink

こういう本は紙の方が便利ですね。


2020年9月12日土曜日

GASで栄養成分表示(推定値)の計算結果を保存する。(指定したフォルダへのスプレッドシートの新規作成 + α)

-----
・追記(2024-9-7)

日本食品標準成分表2023年版対応のスプレッドシートを note にて公開しました。
-----

以前、栄養成分表示(推定値)を計算するスプレッドシートを作りましたが、計算結果の保存はできませんでした。

そのため、原材料や内容量の変更の際に原材料索引番号の検索から計算を始めねばならず面倒でした。ということで、都度手動保存も手間ですので簡単なGASで自動保存できるようにしてみました。

「計算結果」はあらかじめ用意したシートにリストで、「原材料・分量」は指定したフォルダに新しいスプレッドシートを作成してまるっと保存します。計算結果のリストには「原材料・分量」の載ったスプレッドシートへのリンクを記載するようにします。


① 計算結果を保存するシートを追加

以前作った計算用のスプレッドシートに以下のような計算結果を保存するシートを追加します。シート名は「保存された計算結果」にしておきます(後ほど作成するコードでこの名前でシートを指定しているため)。


ダウンロード → 栄養成分計算用スプレッドシート
(ダウンロードは note より)

・追記(2022-8-17)
スプレッドシートを最新版(2020年版対応v02)に差し替えました。

・追記(2021-4-17)
時々、アクセス権のリクエストをいただきますが、↓の方法で編集可能なコピーを作成してご使用ください。

リンクより「保存された計算結果」のシートを追加済みのスプレッドシートをダウンロードできます。PCでGoogleアカウントにログインした状態で、リンク先にて「ファイル」から「コピーを作成」で編集可能なファイルが作成されます。


② フォルダーを準備

商品ごとの原材料・分量を記載したスプレッドシートを保存しておくためのフォルダーを準備(新規作成)します。


③ コードの作成

スプレッドシートの「ツール」→「スクリプト エディタ」からスクリプトファイルを作成します。コードは以下の通りです。

function save() {
    var spsh = SpreadsheetApp.openById("スプレッドシートID");
    var shtIngr = spsh.getSheetByName("原材料・分量の入力");
    var shtCalc = spsh.getSheetByName("栄養成分の計算結果");
    var shtSave = spsh.getSheetByName("保存された計算結果");
    var ingrLastRow = shtIngr.getLastRow();
    var ingrData = shtIngr.getRange(1,1,ingrLastRow,8).getValues();
    var calcData = shtCalc.getRange(2,1,1,7).getValues();
    
    //新しいスプレッドシートの作成
    var fileName = shtCalc.getRange(2,1).getValue() + "_" + shtCalc.getRange(2,2).getValue(); 
    var folderId = "フォルダーID";
    var fileId = SpreadsheetApp.create(fileName).getId();
    var file = DriveApp.getFileById(fileId);
    var folder = DriveApp.getFolderById(folderId);
    folder.addFile(file);    
    DriveApp.getRootFolder().removeFile(file);
    
    //新しいスプレッドシートに原材料を保存
    var newSpsh = SpreadsheetApp.openById(fileId);
    var newSht = newSpsh.getActiveSheet();
    newSht.getRange(1,1,ingrLastRow,8).setValues(ingrData);
    newSht.setFrozenRows(1);
    
    //計算結果を「保存された計算結果」シートに保存
    var newUrl = "https://docs.google.com/spreadsheets/d/" + fileId;
    var listLastRow = shtSave.getLastRow() + 1;
    shtSave.getRange(listLastRow,1,1,7).setValues(calcData);
    shtSave.getRange(listLastRow,8).setValue(newUrl);
}

書き換えが必要なのは2か所です。

・2行目の「スプレッドシートID」

スプレッドシートを開いた状態でURLの下記部分に表示されます。ちょっと長めです。 

https://docs.google.com/spreadsheets/d/ここの値をコピペ/edit#gid=0


・12行目の「フォルダーID」

フォルダーを開いた状態でURLの下記部分に表示されます。こちらもちょっと長め。

https://drive.google.com/drive/folders/ここの値をコピペ


ということで完成です。save関数を実行すると「計算結果」と「原材料・分量」をまとめて保存することができます。

GASの初回実行時に承認が必要となります。無料のGoogleアカウントの場合「このアプリは確認されていません」というページが表示されます。ここで「安全なページに戻る」をクリックすると実行できませんので、「詳細」→「プロジェクト名(安全ではないページ)に移動」から承認します。


GASによるスプレッドシートの新規作成は以下のサイトを参考にさせていただきました。



2020年9月2日水曜日

原木椎茸の有効積算温度の計算


原木椎茸の施設栽培は、2月頃に植菌、それから9月頃までホダ木を作り、秋から収穫を行います。収穫後は休養をはさみ、翌年春までホダ木あたり4回程度収穫します。

原木椎茸の栽培には温度、湿度、水、風、光等、もろもろの環境要素が影響しますので、その土地、その設備に応じて適宜調整をするとこになります。

しかしながらこれまで、雑な言い方をしてしまうと「勘」でこの調整をしていたのですね。もちろん、セオリーとなる栽培方法に沿ってですけども。

そこでスマート農業への取り組みの第一歩として、原木椎茸栽培の定量化を試みてみようと思います。

定量化により、判断基準が明確化し、調整の精度が上がったら素晴らしいですよね。


***

では、ひとつずつ進めていきます。

まずは一番分かりやすい指標となる積算温度の計算です。単位は「℃日」。

原木椎茸の発生に必要な積算温度は4000〜4500℃日程度です(品種による)。有効な温度の計算には森永(1989)によるシイタケ菌の特性に合わせた以下の式を使うことにしました。

T:気温(℃)
TU:有効な温度の量

・T ≦ 5℃ or 32℃ < T
 TU = 0

・5℃ < T ≦ 15℃
 TU = T - 5

・15℃ < T ≦ 23℃
 TU = -46.7 + 20.9 × log( T )

・23℃ < T ≦ 32℃
 TU = 18 - 2 × ( T - 23 )2 / 9

出典:森永鉄美(1989). 「食用きのこの発生と温量(Ⅰ)−有効積算温度の検討−」『日林九支研論集』 No.42, pp.289-290.


グラフにすると以下のようになります。


23℃の時に最も有効な温度の量が多くなります。シイタケ菌の特性がよく分かりますね。

有効積算温度はこの有効な温度の量の総和になります。


スプレッドシートやエクセルではIFS関数を使うと簡単に計算できます。気温がD列に入力してあるとすると以下のようになります。logは自然対数なのでLN関数ですね。

=IFS($D2<=5,0,32<$D2,0,AND(5<$D2,$D2<=15),$D2-5,AND(15<$D2,$D2<=23),-46.7+20.9*LN($D2),AND(23<$D2,$D2<=32),18-2*SUMSQ($D2-23)/9)


上の画像ではE列にこの式が入っています。これをSUM関数で日にち分足すと有効積算温度がでます。


ということで、先日作ったGASで気象データを取得し、外気温(1日の平均気温)での有効積算温度を算出してみました。


すると、今年植菌をした2020年2月から8月いっぱいまでの有効積算温度は2242.9℃日でした。

9月からぼちぼち発生をかけ始めるのですが、必要となる4000〜4500℃日には全く届いていません。やはり2月から5月中頃までの気温が低いのですね。だからこそ、植菌後速やかにシートをかけて保温することが重要となってきます。こうして数値で見ると一つ一つの作業の意味が理解しやすいですね。

来年の植菌までにはデータロガーを入手して、実際のホダ化中の温度をデータ化できるようにしたいと思います。


さてさて、6次化も面白かったですが、スマート化もまた面白さ満点ですね。コツコツ進めたいと思います。


・関連投稿
気象データをGASのWebスクレイピングで自動取得する。


Twitter(@nkkmd)、Instagram(@nkkmd)も日々更新中です。