今回は、以前紹介した「bulkRequestを使った複数アプリの一括処理(在庫管理や予約申請など)」を、kintoneアプリに実装する方法を紹介します。
具体的には、在庫アプリと出庫アプリの2つを使って、「出庫アプリでXX個の出庫を登録すると、在庫アプリの在庫がXX個減る」というしくみを作ります。
また、kintone JavaScript Client(@kintone/rest-api-client)を使用して、REST APIのコードを簡潔にしています。非常に便利なツールなので、これからコードを書く方はぜひ参考にしてみてください。
  デモ環境
    
  
で実際に動作を確認できます。
ログイン情報は
  cybozu developer networkデモ環境
で確認してください。
まずは、完成イメージから見ていきましょう。
在庫アプリはこのような状態です。
  
出庫アプリに出庫数を登録します。
  
すると、出庫アプリには出庫数が登録されます。
  
また、在庫アプリからは在庫数が減りました!
  
在庫が足りない場合は、このようなエラーを表示します。
  
①「在庫数の確認時」と②「在庫数の変更時」のリビジョンが異なる場合(①と②の間に在庫のデータが更新された場合)はこのようなエラーを表示します。
  
これで安全に在庫管理ができますね。
  kintoneの設定
固定リンクがコピーされました
 
  「在庫」アプリの作成
固定リンクがコピーされました
 
| フィールド名 | 
フィールドタイプ | 
フィールドコード | 
備考 | 
| 商品コード | 
文字列(1行) | 
itemCode | 
必須項目にする 値の重複を禁止する
  | 
| 商品名 | 
文字列(1行) | 
itemName | 
必須項目にする
  | 
| 在庫数 | 
数値 | 
stockNum | 
必須項目にする
  | 
  「出庫」アプリの作成
固定リンクがコピーされました
 
| フィールド名 | 
フィールドタイプ | 
フィールドコード | 
備考 | 
| 出庫先 | 
文字列(1行) | 
destination | 
 | 
| 商品コード | 
ルックアップ | 
itemCode | 
必須項目にする 関連付けるアプリ:在庫アプリ コピー元のフィールド:商品コード ほかのフィールドのコピー:「商品名」に「在庫アプリの商品名」
  | 
| 商品名 | 
文字列(1行) | 
itemName | 
 | 
| 出庫数 | 
数値 | 
pickNum | 
必須項目にする
  | 
  「出庫」アプリのJS/CSS設定
固定リンクがコピーされました
 「アプリの設定 > JavaScript / CSSでカスタマイズ」の「PC用のJavaScriptファイル」に以下のURL/ファイルを設定します。
- kintone JavaScript Client(@kintone/rest-api-client)
以下のURLを指定します。
https://js.cybozu.com/kintone-rest-api-client/5.5.2/KintoneRestAPIClient.min.js 
- 以下のサンプルコードを参考に、ファイル名を「sample.js」、文字コードを「UTF-8」で保存、アップロードします。
ファイル名は任意ですが、ファイルの拡張子は「js」にしてください 
  
    
    
  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
  | 
/*
 * kintoneで安全に在庫を行うサンプルプログラム
 * Copyright (c) 2024 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
*/
(() => {
  'use strict';
  kintone.events.on('app.record.create.submit', async (event) => {
    // 保存するレコードの情報を取得
    const outBoundRecord = event.record;
    // 在庫管理アプリのアプリIDを取得
    const stockAppId = kintone.app.getLookupTargetAppId('itemCode');
    // 出庫管理アプリのアプリIDを取得
    const outBoundAppId = kintone.app.getId();
    // 出庫数を取得
    const pickNum = Number(outBoundRecord.pickNum.value);
    // 出庫先を取得
    const destination = outBoundRecord.destination.value;
    // 商品コードを取得
    const itemCode = outBoundRecord.itemCode.value;
    try {
      // KintoneRestAPIClientのインスタンスを作成
      const client = new KintoneRestAPIClient();
      // 在庫管理アプリから該当商品のレコードを取得
      const {records: stockRecords} = await client.record.getRecords({
        app: stockAppId,
        query: 'itemCode = "' + itemCode + '"',
        fields: ['$id', '$revision', 'stockNum']
      });
      // 商品レコードが1件取得できなかった場合はエラーを返す
      if (stockRecords.length !== 1) {
        event.error = '商品が特定できません。';
        return event;
      }
      // 現在の在庫数を取得
      const stockNum = Number(stockRecords[0].stockNum.value);
      // 出庫後の在庫数を計算
      const newStockNum = stockNum - pickNum;
      // 在庫が足りない場合はエラーメッセージを表示して終了
      if (newStockNum < 0) {
        event.error = `在庫が足りません。今の在庫数は ${stockNum} です。`;
        return event;
      }
      // 在庫管理アプリのレコード更新と出庫管理アプリのレコード登録のリクエストを設定
      const params = {
        requests: [
          // 在庫管理アプリの在庫数更新
          {
            method: 'PUT',
            api: '/k/v1/record.json',
            payload: {
              app: stockAppId,
              id: stockRecords[0].$id.value,
              record: {
                stockNum: {value: newStockNum}
              },
              revision: stockRecords[0].$revision.value
            }
          },
          // 出庫管理アプリの出庫情報登録
          {
            method: 'POST',
            api: '/k/v1/record.json',
            payload: {
              app: outBoundAppId,
              record: {
                destination: {value: destination},
                itemCode: {value: itemCode},
                pickNum: {value: pickNum}
              }
            }
          }
        ]
      };
      try {
        // 在庫更新と出庫登録をbulkRequestで同時に実行
        const bulkResp = await client.bulkRequest(params);
        // 登録した出庫情報の詳細ページにリダイレクト
        location.href = '/k/' + outBoundAppId + '/show#record=' + bulkResp.results[1].id;
        // レコードの保存はbulkRequest内で実行済みなので、
        // 保存イベントの動作はキャンセルする
        return false;
      } catch (err) {
        // bulkRequestに失敗した場合のエラーハンドリング
        console.log(err);
        event.error = '出庫に失敗しました。';
        return event;
      }
    } catch (err) {
      // 在庫管理アプリから商品のレコード取得に失敗した場合のエラーハンドリング
      console.log(err);
      event.error = '商品を取得できませんでした。';
      return event;
    }
  });
})();
  | 
 
 
     
   
ポイントは以下の3つです!
- bulkRequest(kintoneBulkRequest)を使って、2つのアプリ(在庫、出庫)を同時に操作します。
 
- bulkRequestによる在庫アプリの更新時にはリビジョンを指定します。
 
- bulkRequestが成功した場合は「return false」として、レコードの登録自体はキャンセルします。(93行目)
 
kintoneでは、各レコードの更新履歴をリビジョン(revision)で管理しています。
レコード作成時にはリビジョンが1に設定され、その後、レコードを保存するたびにリビジョン番号が1ずつ増加します。
sample.jsでは、出庫時にまず在庫管理アプリから在庫情報を取得します。
この際に取得したリビジョン値は、その時点での最新の状態を表す値となります。
その後、出庫後の在庫数を計算し、レコードを更新する際に、取得したリビジョン値を指定します。
更新処理では、指定されたリビジョンと現在のレコードのリビジョンが比較されます。
両方のリビジョンが一致している場合のみ、更新処理が実行されます。
一致しない場合は、取得から更新までの間に他のプロセスでレコードが変更されたことを意味し、衝突を防ぐために更新処理は中止されます。
詳細は次のAPIドキュメントを参考ください。
  1件レコード更新時のパラメータ
  更新時にリビジョンを指定しない場合
固定リンクがコピーされました
 レコード更新時にリビジョンを指定しない場合、リビジョン番号は検証されません。
意図せず他の変更を上書きしてしまうリスクがありますが、複数のデータを一括で更新する場合や、競合リスクが低いケースでは便利に活用できることもあります。
リビジョンの使い方わかりましたでしょうか。
サンプルコードはレコードの登録、出庫にしか対応していません。
ぜひレコードの編集や入庫にも対応させてみてください。
- 2019/06/10
- 利用ライブラリをkintone Utility Library for JavaScriptからkintone JS SDKに変更
 
 
- 2024/07/25
- 利用ライブラリをkintone JS SDKからkintone JavaScript Clientに変更