kintoneで使える関数を作ってみた

はじめまして！
kintone Advent Calendar 22日目 になりました。
昨年は指をくわえて、Advent Calendarを眺めてましたが、今回は記事を投稿する側として参戦させて頂きました。

# 簡単に自己紹介
kitnone cafe 埼玉の事務局メンバーとして活動してたりします。

直近の活動報告など。
http://kintonecafe.com/2016/10/kintone-cafe-saitama-vol3-now/
 
お近くでご興味ある方は是非遊びにいらして下さい！
1月に kintone cafe 埼玉 vol.4 を予定しています！

# kintone内で利用できる便利な関数
#### **SUM** 
足し算を行います。次の書式で使用します。
SUM（数値1, 数値2, 数値3, ・・・）
「数値」には、「数値」フィールドのコード、値が数値になる計算式、または数値を指定します。
+演算子と同等のことができるほか、テーブル内にあるフィールドの値の和を計算できます。

#### **YEN**
計算結果を「¥（円）」形式で表示できます。計算結果は、3桁区切りで表示されます。
また、指定した桁数で四捨五入されます。
YEN関数は、「文字列（1行）」フィールドでだけ使用できます。
「数値」フィールドの値を¥形式で表示する場合、単位記号を設定します。
YEN関数は、次の書式で使用します。
YEN(数値, 四捨五入の桁数)
「数値」には、「数値」フィールドのコード、値が数値になる計算式、または数値を指定します。
「桁数」には、四捨五入する小数点以下の桁数を指定します。負の数値を指定すると、正の桁で四捨五入されます。

※参考 : [kintoneユーザーヘルプ](https://help.cybozu.com/ja/k/user/autocalc_format.html "kintoneユーザーヘルプ")

**以上です。**

# あれ・・・思ったより少ない・・・
そうなんです！
今は、この2種類しか使えないので、今回使える関数を増やしてみました。

## kintoneアプリの準備

まずはkintone側の準備をします。
今回は関数の中でも割と簡単(?)な**AVG**関数を作ってみました。

| **フィールド名** | **フィールドコード** | **フィールドの型** | **備考** |
|:-:|:-:|:-:|:-:|
|氏名|NAME|文字列_1行|テーブル|
|算数の点数|MATH_POINTS|数値|テーブル|
|国語の点数|NATIONAL_LANGUAGE_POINTS|数値|テーブル|
|Excel関数|EXCEL_FUNCTION|ドロップダウン|'AVG'|
|計算対象|CALC_TARGET|ドロップダウン|'算数の点数'<br>'国語の点数'|
|計算結果|CALC_RESULT|数値||
|指定行数<br>(から)|ROW_FROM|数値||
|指定行数<br>(まで)|ROW_TO|数値||

上記を設定したら、
早速登録画面を表示してみましょう。

![Qiita1.png](https://qiita-image-store.s3.amazonaws.com/0/31985/21646224-cd12-9f46-b694-dbe9defdff66.png)

※ラベルとかは適宜入れています。

この時点では、もちろん何もしてませんので、
何を選択しても何も反応しません。

ここから、Excel関数のドロップダウンで**AVG**が選択されたら、
計算対象の点数の平均値を計算結果に反映する。というのを行いたいと思います。

また、オプション的に、
計算範囲で選択された〇〇行 ~ 〇〇行までを対象とする。

というようなものにしようかと思います。

## デフォルト表示を少し変える ##

デフォルト表示のままだと、Excel関数が増えてきた場合に、
どの項目に何を設定すればいいのか、ユーザーが困ってしまいますので、
レコード作成画面表示時とレコード編集画面表示時、レコード詳細画面表示時の
表示を少しだけカスタマイズします。


```javascript:index.js
jQuery.noConflict();
(function($) {
    "use strict";
     
    var EXCEL_FUNCTION = {
        "AVG" : "AVG"
    };
    
    var CALC_TARGET = {
        "MATH" : "算数の点数",
        "NATIONAL_LANGUAGE" : "国語の点数"
    }
     var default_hide_item = function() {
         kintone.app.record.setFieldShown("CALC_TARGET", false);
         kintone.app.record.setFieldShown("CALC_RESULT", false);
         kintone.app.record.setFieldShown("ROW_FROM", false);
         kintone.app.record.setFieldShown("ROW_TO", false);
         $("span.control-value-label-gaia").eq(0).css("display", "none");
         $("span.control-value-label-gaia").eq(1).css("display", "none");
         $("span.control-value-label-gaia").eq(2).css("display", "none");
     }
     
     var avg_hide_item = function(record) {
         kintone.app.record.setFieldShown("CALC_TARGET", true);
         kintone.app.record.setFieldShown("CALC_RESULT", true);
         kintone.app.record.setFieldShown("ROW_FROM", true);
         kintone.app.record.setFieldShown("ROW_TO", true);
         $("span.control-value-label-gaia").eq(0).css("display", "inline");
         $("span.control-value-label-gaia").eq(1).css("display", "inline");
         $("span.control-value-label-gaia").eq(2).css("display", "inline");
         record["CALC_RESULT"].disabled = true;
     }
     kintone.events.on(['app.record.create.show', 'app.record.edit.show', 'app.record.detail.show'], function(event) {
         var record = event.record;
         if (record["EXCEL_FUNCTION"].value == EXCEL_FUNCTION.AVG) {
             avg_hide_item(record);
         } else if (record["EXCEL_FUNCTION"].value == null) {
             default_hide_item();
         }
         return event;
     });
})(jQuery);
```

これによってユーザーの入力が迷いにくくなったと思います。(自己満足)

**初期表示**
![Qiita3.png](https://qiita-image-store.s3.amazonaws.com/0/31985/bb1166be-76b6-a0af-8636-c8f1076a728a.png)

**AVGを選択**
![Qiita4.png](https://qiita-image-store.s3.amazonaws.com/0/31985/9a40fa0e-8392-7095-7fe1-21adc360e93f.png)

これで、表示設定は完了です。
ユーザーもきっと使いやすくなったと感動してくれることでしょう。(自己満足2回目)

あとは、平均算出のロジックをjavascriptで実装していきます。

## 平均算出ロジックを実装してみる。 ##

指定行数の値に変更がある場合に動作するように実装してみました。

```javascript:index.js
     var avg_row_change_event = ['app.record.create.change.ROW_FROM', 'app.record.edit.change.ROW_FROM', 'app.record.create.change.ROW_TO', 'app.record.edit.change.ROW_TO'];
     kintone.events.on(avg_row_change_event, function(event) {
         var record = event.record;
         var table_length = $("button.add-row-image-gaia").length;
         record["CALC_RESULT"].value = avg_calc(record);
         return event;
     });
     
     /**
      * 平均算出ロジック
      */
     var avg_calc = function(record) {
         var row_from = record["ROW_FROM"].value == null ? 0 : (record["ROW_FROM"].value > 0 ? record["ROW_FROM"].value : 1);
         var row_to = record["ROW_TO"].value;
         
         var arrays = record["Table"].value;
         var total = 0;
         if (record["EXCEL_FUNCTION"].value == EXCEL_FUNCTION.AVG) {
             if (record["CALC_TARGET"].value != null && record["CALC_TARGET"].value == CALC_TARGET.MATH) {
                 $.each(arrays, function(index, row) {
                     if (row_from <= index + 1 && (row_to != null && row_to >= index + 1)) {
                         total += parseInt(row.value["MATH_POINTS"].value);
                     } else if (row_from <= index + 1 && row_to == null) {
                         total += parseInt(row.value["MATH_POINTS"].value);
                     }
                 });
                 
             } else if (record["CALC_TARGET"].value != null && record["CALC_TARGET"].value == CALC_TARGET.NATIONAL_LANGUAGE) {
                 var total = 0;
                 $.each(arrays, function(index, row) {
                     if (row_from <= index + 1 && (row_to != null && row_to >= index + 1)) {
                         total += parseInt(row.value["NATIONAL_LANGUAGE_POINTS"].value);
                     } else if (row_from <= index + 1 && row_to == null) {
                         total += parseInt(row.value["NATIONAL_LANGUAGE_POINTS"].value);
                     }
                 });
             }
         }
         var div_num;
         if (row_to == null) {
             div_num = parseFloat(total / ((arrays.length + 1) - parseInt(row_from)));
         } else {
             div_num = parseFloat(total / (parseInt(row_to - row_from) + 1));
         }
         div_num = div_num * 100;
         div_num = Math.ceil(div_num) // 切り上げ
         div_num = parseFloat(div_num / 100);
         
         return div_num
     }

```

ここまで実装出来ると、こんな感じになります。
![Qiita5.png](https://qiita-image-store.s3.amazonaws.com/0/31985/d87c518e-a5b9-759d-2137-9c6d2df2c069.png)

無事に計算結果が算出されました。
今回は**AVG**関数だけの実装になってしまいましたが、
今後もユースケースを踏まえて、カスタマイズを楽しみましょうー！

**標準機能で出来ると嬉しいな！！！**