予算アプリと実績アプリの集計表をカスタマイズビューに表示する

目次

caution
警告

概要

こちらのサンプルは、予算管理アプリと実績管理アプリのデータを使って、予算/実績の差異と達成率を計算し、集計表に表示させるカスタマイズです。

カスタマイズビューという機能を利用し、ひとつの集計表にデータをまとめられるので、複数のアプリを確認したり、手動で集計したりする手間を省くことができます。
カスタマイズの適用方法は、「 適用手順」を参照してください。

完成形

デモ環境

デモ環境で実際に動作を確認できます。

ログイン情報は cybozu developer network デモ環境 で確認してください。

下準備

適用手順

今回のカスタマイズは、「実績管理」アプリが対象です。

カスタマイズビューの設定

アプリストアから「 予算・実績管理 (External link) 」を追加した場合、この設定は不要です。
また、カスタマイズビューを作成するには、kintone の管理権限が必要です。

  1. 一覧を追加します。

  2. 新規に一覧を作成し「レコード一覧の表示形式」を「カスタマイズ」に設定します。

  3. HTML 欄に次の HTML を入力し保存します。

    1
    2
    
    <table id="view"></table>
    <div id="pager"></div>

カスタマイズビューの設定方法の詳細は、 カスタマイズする場合 | kintone ヘルプ (External link) を参照してください。
また、カスタマイズビューの使い方について、チュートリアル記事「 第 7 回 カスタマイズビューを利用してみよう」により詳しい解説がありますので、
興味ある方はぜひそちらも確認してください。

JavaScriptファイル / CSS ファイルの追加

カスタマイズに必要なライブラリを追加します。

  1. アプリの設定画面から、「JavaScript / CSS によるカスタマイズ」を開きます。
  2. 次の内容を設定します。

    項目 設定する値
    PC用のJavaScriptファイル 次の順で、URL およびファイルを指定します。
    • https://js.cybozu.com/jquery/2.2.4/jquery.min.js
    • https://js.cybozu.com/jqueryui/1.11.4/jquery-ui.min.js
    • jqGrid のファイル
      入手方法は jqGrid を参照してください。
      • jQuery.jqGrid.min.js
      • grid.locale-ja.js
    • sample_grid.js
      サンプルプログラム のコードをエディターにコピーし、文字コードを「UTF-8(BOMなし)」、拡張子を「js」にしてファイルを保存します。
      ファイル名は任意です。ここでは「sample_grid.js」としています。
    PC用のCSSファイル 次の順で、URL およびファイルを指定します。
    • https://js.cybozu.com/jqueryui/1.11.4/themes/redmond/jquery-ui.css
    • ui.jqgrid.css(jqGrid のファイルの入手方法は jqGrid を参照してください)
    適用対象 カスタマイズを適用するユーザーやグループを選択します。
jqGrid
caution
警告

カスタマイズで利用している jqGrid は、v4.7.1 以降 MIT ライセンスではなくなりました。
このカスタマイズでは、 MIT (External link) / GPLv2 (External link) ライセンスの v4.7.0 を利用しています( ライセンス表記 (External link) )。
v4.7.1 以降を利用する際は Guriddo の HP (External link) で有償ライセンスを購入し、ライセンス条件にしたがって利用してください。
詳細は、 Cybozu CDN ライセンス対応ガイド を参照してください。

jqGrid は https://github.com/tonytomov/jqGrid/releases/tag/v4.7.0 (External link) の「Source code(zip)」からダウンロードしてください。
ダウンロードした zip ファイルを解凍した後、次のファイルを利用します。

  • jQuery.jqGrid.min.js:js > minified ディレクトリーの下
  • grid.locale-ja.js:js > i18n ディレクトリーの下
  • ui.jqgrid.css:css ディレクトリーの下

サンプルプログラム

  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
134
135
136
137
/*
 * カスタマイズビューのサンプルプログラム
 * Copyright (c) 2016 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */
jQuery.noConflict();
(($) => {

  'use strict';
  // 予算管理アプリを全レコード取得
  const fetchRecords = (app_yosan, opt_offset, opt_limit, opt_records) => {
    const offset = opt_offset || 0;
    const limit = opt_limit || 100;
    let allRecords = opt_records || [];
    const params = {app: app_yosan, query: 'order by レコード番号 asc limit ' + limit + ' offset ' + offset};
    return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', params).then((resp) => {
      allRecords = allRecords.concat(resp.records);
      if (resp.records.length === limit) {
        return fetchRecords(app_yosan, offset + limit, limit, allRecords);
      }
      return allRecords;
    });
  };
  // 予実管理データのカスタマイズビュー用データの作成
  const makeYojitsuData = (records, opt_data, opt_i) => {
    let i = opt_i || 0; // レコードのカウント
    const allData = opt_data || []; // 予実の集計結果
    const appId = kintone.app.getId(); // 実績管理アプリID
    let key1, key3, key4, key5;
    key1 = records[i]['拠点'].value;
    key1 = key1.replace(/</g, '&lt;').replace(/>/g, '&gt;');
    const key2 = records[i]['予算'].value;

    const params = {app: appId, query: '拠点 = "' + key1 + '"'};
    return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', params).then((resp) => {
      if (resp.records) {
        key3 = 0;
        const obj = resp.records;
        for (let j = 0; j < obj.length; j++) {
          key3 += parseInt(obj[j]['実績合計'].value, 10);
        }
        key4 = parseInt(key3, 10) - parseInt(key2, 10);
        key5 = parseInt(key3, 10) / parseInt(key2, 10) * 100;
        key5 = key5.toFixed(2);
        key5 += '%';
        allData.push({segment: key1, budget: key2, results: key3, Difference: key4, AchievementRate: key5});
      } else {
        event.error = '実績管理情報が取得できません。';
      }
      i += 1;
      if (records.length !== i) {
        return makeYojitsuData(records, allData, i);
      }
      return allData;
    });
  };
  // 差異のマイナス値を赤色に変更
  const cellDesign = () => {
    $('#view tr td').each((index, elm) => {
      if ($(this).hasClass('Difference_class')) {
        if ($(this).text().indexOf('-') > -1) {
          $(this).css('color', '#ff0000');
        }
      }
    });

  };
  // 予実管理のカスタマイズビューを取得
  const dispYojitsuCustomizeView = (records) => {
    makeYojitsuData(records).then((data) => {
      // 列の設定
      const colModelSettings = [
        {name: 'segment',
          index: 'segment',
          width: 300,
          align: 'center',
          classes: 'segment_class'},
        {name: 'budget',
          index: 'budget',
          width: 200,
          align: 'right',
          classes: 'budget_class',
          formatter: 'currency',
          sorttype: 'float'},
        {name: 'results',
          index: 'results',
          width: 200,
          align: 'right',
          classes: 'results_class',
          formatter: 'currency',
          sorttype: 'float'},
        {name: 'Difference',
          index: 'Difference',
          width: 200,
          align: 'right',
          classes: 'Difference_class',
          formatter: 'currency',
          sorttype: 'float'},
        {name: 'AchievementRate',
          index: 'AchievementRate',
          width: 150,
          align: 'center',
          classes: 'AchievementRate_class',
          sorttype: 'float'}
      ];
      // 列の表示名
      const colNames = ['拠点', '予算', '実績', '差異', '達成率'];
      $('#view').jqGrid({
        data: data,
        datatype: 'local',
        colNames: colNames,
        colModel: colModelSettings,
        rowNum: 10,
        rowList: [1, 10, 20],
        caption: '売上',
        height: 'auto',
        width: 1100,
        pager: 'pager',
        shrinkToFit: true,
        viewrecords: true,
        gridComplete: () => {
          cellDesign();
        }
      });
    });
  };
  // イベント処理
  kintone.events.on(['app.record.index.show'], (event) => {
    const app_yosan = kintone.app.getLookupTargetAppId('拠点'); // 予算管理アプリID
    fetchRecords(app_yosan).then((records) => {
      dispYojitsuCustomizeView(records);
    });
  });

})(jQuery);

注意事項

kintone JavaScript API は非同期で実行されるため、XMLHttpRequest を使って同期処理しています。

処理中はブラウザーがフリーズする場合があります。

また、XMLHttpRequest は利用できないブラウザーもありますので、ご注意ください。

使用したAPI

  1. イベントハンドラーを登録する
  2. レコード一覧画面を表示した後のイベント
  3. アプリの ID を取得する
  4. ルックアップフィールドの参照先のアプリ ID を取得する
  5. kintone REST API リクエストを送信する
  6. API の URL を取得する