第 11 回 kintone REST API を利用したレコード更新(ルックアップ自動更新)

目次

information

初めてkintoneをカスタマイズする人がkintone APIの基礎知識を学べるよう、チュートリアルの内容を充実させてリニューアルしました。
リニューアル後のチュートリアルは次のページを参照してください。
はじめよう kintone API

はじめに

前回はkintone REST APIを利用し、アプリ情報やレコード情報の取得を取り扱いました。
今回は、kintone REST APIを利用したレコードの更新(ルックアップ自動更新)を扱います。
頑張っていきましょう。

ルックアップについて

ルックアップは、登録/更新時にコピー元からデータを取得し、コピー先フィールドにデータをコピーします。
しかし、コピー元のデータを更新してもコピー先フィールドは変更されません。

ということで、ルックアップの自動更新にチャレンジしてみましょう。

アプリの準備

今回は、顧客マスターアプリと顧客マスターアプリをルックアップしている見積もり管理アプリを使います。

顧客マスターアプリ

次のような顧客マスターアプリを用意します。

フィールド名 フィールドタイプ フィールドコード 備考
レコード番号 レコード番号 レコード番号
会社 文字列(1行) company 必須項目
部署 文字列(1行) post
電話番号 リンク tel 入力値の種類:電話番号

この顧客マスターアプリにJavaScriptを登録することで、ルックアップの自動更新を実現します。

見積もり管理アプリ

次のような見積もり管理アプリを用意します。

フィールド名 フィールドタイプ フィールドコード 備考
ルックアップ ルックアップ lookup 関連付けるアプリ:顧客マスター
コピー元のフィールド:レコード番号
ほかのフィールドのコピー:
  • 会社⇐[顧客マスター]会社
  • 部署⇐[顧客マスター]部署
  • 電話番号⇐[顧客マスター]電話番号
コピー元のレコード選択時に表示するフィールド:会社、部署
会社 文字列(1行) company 必須項目
部署 文字列(1行) post
電話番号 リンク tel 入力値の種類:電話番号
テーブル テーブル Table
テーブル[製品] 文字列(1行) product
テーブル[個数] 数値 個数 最小値:0以上
テーブル[単価] 数値 単価 最小値:0以上
単位:¥
テーブル[価格] 計算 price 計算式:個数*単価
単価計算式を表示しない単位:¥
小計 計算 subtotal 計算式:SUM(price)
計算式を表示しない単位:¥
消費税 計算 tax 計算式:subtotal*0.08
計算式を表示しない単位:¥
合計 計算 total 計算式:subtotal+tax
計算式を表示しない単位:¥

レコード番号で顧客マスターアプリからルックアップし、「会社」「部署」「電話番号」をコピーします。
作成できたら、アプリIDは後で使うので控えておいてください。

実装する処理を整理

コーディングを始める前に、今回やりたいことと、実現するための処理の流れを考えてみましょう!

やりたいこと

  • 顧客マスターアプリの情報が更新されたとき、見積もり管理アプリに登録されたデータも更新する。

実装する処理

顧客マスターアプリで、レコードが更新されたときに以下の処理を行います。

  1. 見積もり管理アプリの対象レコードを一括取得
  2. レコード更新用のデータを準備し、1の対象レコードを一括更新
  3. 処理の成功、失敗を知らせるメッセージを表示

別アプリのデータを更新するので、更新処理がうまくいったかどうかを実行後にメッセージでお知らせしましょう!
1~3は処理の順番を守る必要がある、ということが重要なポイントになってきます。
それでは、JavaScriptの処理を書いていきましょう!

更新時イベント

今回の処理は、顧客マスターアプリのレコード更新時に行います!

レコード保存時に行われるイベントには、「保存するとき(保存ボタンを押したとき)」と「保存に成功した後」の2種類があります。
編集画面なら次のイベントです。

また、フィールドの設定画面から「必須」や「値の重複の禁止」などを設定しておくと、こちらも保存前にチェックされてエラーメッセージが表示されますね。
ここでは「製品標準の入力チェック」と呼ぶことにします。

これらの保存イベントや製品標準の入力チェックは、次の順番で実行されます。

  1. 保存するときのイベントが発生
  2. 製品標準の入力チェック(必須、重複禁止、型チェック等)
  3. レコードの保存処理
  4. 保存に成功した後のイベントが発生

第 8 回は「編集中レコードの値を、保存前に書き換える処理」だったため、1の「保存するときのイベント」を利用しました。

今回は、「入力チェックをすべて通って、レコードに保存された値」を使って別アプリのレコードを更新する必要があるので、4の「保存に成功した後のイベント」を利用しましょう!

レコードの編集は、レコード画面とレコード一覧画面の2ヵ所で行うことができるため、以下の2つのイベントを使います。

1
2
3
4
5
6
7
8
9
(() => {
  'use strict';

  // 保存成功後イベント
  kintone.events.on(['app.record.edit.submit.success', 'app.record.index.edit.submit.success'], (event) => {
    // ここに処理の内容を記述する

  });
})();

もうお馴染みの形ですね。

更新が必要なレコードの一括取得

レコードの一括取得は、 前回の記事で学びました。

1
2
3
4
5
6
7
8
const paramGet = {
  app: updateAppId,
  query: 'lookup = ' + event.record['レコード番号'].value
};

kintone.api(kintone.api.url('/k/v1/records', true), 'GET', paramGet, (resp) => {
  // レコード取得後の処理
});

「レコード一括取得後の処理」というコメントのところに、このあとやりたい処理を書き足してくことになります。
次の2と3の部分ですね。

  1. 見積もり管理アプリの対象レコードを一括取得
  2. レコード更新(ルックアップの内容を更新)するためのデータを準備
  3. 2のデータを使って、見積もり管理アプリの対象レコードを一括更新

2と3は、処理の順番も重要です。
でも先ほどの書き方の中に2と3を組み込んでしまうと、2と3が同時に動いてしまうため処理順は守られません。

そこで、「順番とおりに処理を実行してもらう」ために、PromiseというJavaScriptの書き方を使います!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const paramGet = {
  'app': updateAppId,
  'query': 'lookup = ' + event.record['レコード番号'].value
};
return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', paramGet).then((resp) => {
  // ルックアップの更新
}).then((resp2) => {
  // 処理成功のメッセージを表示
}).catch((error) => {
  // エラー表示をする
});

Promiseについては、ここでは詳しく解説しませんが、次のことだけ覚えておいてください。

  • .thenで順番に実行する処理をつなぐ。
  • エラーは.catchで拾える。

Promiseについて勉強したい方は、この記事の最後にリンクを貼った記事を参考にしてください。
また、 複数のレコードを取得する APIでレコードを取得する場合、デフォルトでは一度に100件まで取得できます。
「query」パラメーターの「limit」オプションを使用すると、一度に500件まで取得できます。
500件以上のレコードのルックアップを自動更新したい場合は、 offset の制限値を考慮したレコード一括取得についてなどを参考にしてください。
今回は100件までの場合のみの説明になります。

ルックアップの一括更新

ここで、 複数のレコードを取得する APIのドキュメントを確認してみましょう。

リクエストパラメーター

パラメーター名idupdateKeyのどちらかを指定する必要があります。
両方を指定すると、エラーになります。

パラメーター名 指定する値 必須 説明
app 数値または文字列 必須 アプリの ID を指定します。
records 配列 必須 更新するレコードの情報を指定します。
本パラメーターの値は、更新したいレコードIDと更新したいレコード情報をセットにしたオブジェクトを配列で記述します。
records.id 数値または文字列 省略可
updateKeyを指定する際には指定不可
更新するレコードの番号
records 配列内に記述します。
records.updateKey Object 省略可
idを指定する際には指定不可
重複禁止フィールドコードと値を指定します。
指定できるフィールドは重複を禁止が設定された文字列(1 行)と数値のみです。
records.record Object 省略可 レコードの情報(フィールドコードとフィールドの値)をオブジェクトで指定します。
フィールド値の仕様についてはフィールドの形式により異なります。
詳細については フィールド形式を確認してください。
省略した場合は、データは更新されません。
records.revision 数値または文字列 省略可 期待しているリビジョン番号
実際のリビジョン番号と一致しない場合はエラーとなります(いずれのレコードも更新しない)。
ただし、値が-1あるいは指定しなかった場合はリビジョン番号の検証を行いません。

必要なパラメーターは、「アプリID」「更新したいレコードID」「更新したいレコード情報をセットにしたオブジェクト」の3つですね。
というわけで、更新したいレコードIDと更新したいレコード情報をセットにしたオブジェクトを作成する関数を用意しておきましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/*
* kintone REST APIで一括更新するrecordsデータを作成する関数
* @param records kintone REST APIで一括取得したrecordsデータ
* @returns {Array} kintone REST APIで一括更新するrecordsデータ
*/
const createPutRecords = (records) => {
  const putRecords = [];
  for (let i = 0, l = records.length; i < l; i++) {
    const record = records[i];
    putRecords[i] = {
      id: record.$id.value,
      record: {
        lookup: {
          value: record.lookup.value
        }
      }
    };
  }
  return putRecords;
};

更新するフィールドは、ルックアップのみとなります。
このレコードの更新情報を使ってkintone REST APIで一括更新することで、コピー先フィールドを更新できます。

ここまで来ると、あとは複数のレコードを取得するAPIを使って更新するだけですね。

1
2
3
4
5
6
7
// ルックアップの更新
const records = resp.records;
const paramPut = {
  app: updateAppId,
  records: createPutRecords(records)
};
return kintone.api(kintone.api.url('/k/v1/records', true), 'PUT', paramPut);

こちらも、Promiseに対応した書き方をしています。
そして更新したいレコードデータは、先ほど書いたcreatePutRecords()関数を呼び出して取得しました。

まとめるとこんな感じのJavaScriptになります。
見積もり管理のアプリのアプリIDは環境によって変えてください。

 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
/*
 * ルックアップ更新のサンプルプログラム
 * Copyright (c) 2019 Cybozu
 *
 * Licensed under the MIT License
 */
(() => {
  'use strict';

  // 見積もり管理アプリのアプリID
  const updateAppId = 15;

  /**
   * kintone REST APIで一括更新するrecordsデータを作成する関数
   * @param records kintone REST APIで一括取得したrecordsデータ
   * @returns {Array} kintone REST APIで一括更新するrecordsデータ
   */
  const createPutRecords = (records) => {
    const putRecords = [];
    for (let i = 0, l = records.length; i < l; i++) {
      const record = records[i];
      putRecords[i] = {
        id: record.$id.value,
        record: {
          lookup: {
            value: record.lookup.value
          }
        }
      };
    }
    return putRecords;
  };

  // 保存成功後イベント
  kintone.events.on(['app.record.edit.submit.success', 'app.record.index.edit.submit.success'], (event) => {

    // レコードの一括取得(100件まで)
    const paramGet = {
      app: updateAppId,
      query: 'lookup = ' + event.record['レコード番号'].value
    };
    return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', paramGet).then((resp) => {

      // ルックアップの更新
      const records = resp.records;
      const paramPut = {
        app: updateAppId,
        records: createPutRecords(records)
      };
      return kintone.api(kintone.api.url('/k/v1/records', true), 'PUT', paramPut);

    }).then((resp2) => {

      // 処理成功
      alert('ルックアップの更新が完了しました!');
      return event;

    }).catch((error) => {

      // エラー表示をする
      alert('ルックアップの更新でエラーが発生しました。\n' + error.message);
      return event;

    });
  });
})();

では、このJavaScriptを顧客マスターアプリに登録しレコードを更新してみましょう。

こんな感じでレコードを編集し保存するとアラートが表示されましたね!

では、見積もり管理アプリのルックアップしているレコードに更新内容が反映されているか確認してみましょう。

バッチリですね。

最後に

今回は、kintone REST APIを使ってルックアップを自動更新する方法を紹介しました!
しかし、今回のサンプルだと100件までしかルックアップの自動更新ができないので、 offset の制限値を考慮した kintone のレコード一括取得についてを参考にして実装してみてください。

参考リンク

information

このTipsは、2022年7月版kintoneで動作を確認しています。

デモ環境

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

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