kintoneの編集画面とFormBridge&kViewerで、どちらもルックアップを使いたい
トヨクモ_kintone連携サービス Advent Calendar 2024に参加させていただきました。
今回は、職場でFormBrideでkViewerルックアップ使ってて、ちょっと困ったことの自分流の解決策を共有します。
前提条件
電子申請をしてもらう際に、施設をルックアップで選択したい。
選択した施設の、施設名やカナ、電話番号、その他の情報なんかもkintoneに一括で登録したい。
電子申請できない人も居るので、FAXや電話申請も受け付ける。これらはkintoneで職員が入力するので、ルックアップ機能を使いたい。
さらっと考えて気づくこと
(1)(2)は、まさに、FormBridgeとkViewerルックアップがうってつけ!施設マスタ作ってればきっと余裕!
(3)は、kintoneにルックアップがあるから、これも余裕!
どうやら、kintoneとFormBridgeとkViewerで簡単に解決できそうです。
でも、実はここに大きな落とし穴が……
https://guide.kintoneapp.com/formbridge/specification/
そう、実は、FormBridgeでは、kintoneの「ルックアップ」フィールドや「ほかのフィールドをコピー」に指定したフィールドにはデータを格納できないんです。
つまり、「電子申請でもkintoneでも同じ部分にルックアップを設定する」ことは、普通にはできないんですね。
今回は外部からの電子申請ですが、例えば、
こんな風に、kintoneのライセンスを抑えるためにFormBridgeを使う場合も、FormBridgeとkintoneで同じようにルックアップを使うことは課題になっちゃいます。
なんとかできないかってことで、自分なりに松竹梅で3コース考えてみました。(ちなみに、自分は環境上、竹コースを採用しました。)
解決策
【梅コース】kintoneのCSVエクスポートとインポートを使う。
FormBridgeからkintoneの「ルックアップ」フィールドにデータは格納できない。じゃあ、FormBridgeからの格納用に「文字列(1行)」のフィールドを作って、そこにルックアップのデータを格納し、kintoneのCSVエクスポートを使って該当データを吐き出した後、フィールド名を変更してインポートしちゃおうっていう方法です。
kintoneって、「ルックアップ」フィールドにデータをインポートすると「ほかのフィールドをコピー」も自動的に反映してくれるんですね。とっても便利です(ルックアップのマスタ側の文字列に「値の重複を禁止する」のチェックが必要です)。
これで目的は達成できますが、担当者が定期的にエクスポート・インポートを行う必要があるので、少し面倒です。
【竹コース】カスタマイズでボタン一発で処理
基本的な考え方は梅コースと同じです。ただ、アプリをカスタマイズして、ボタン一発で内部的に同じような処理をしてみました。
なお、今回のカスタマイズには、以下の2つのライブラリを利用しています。利用しなくてもカスタマイズは可能ですが、特にkintone REST API Clientは、使うとコードがとってもシンプルになって見やすくなります(少しカスタマイズを経験した人だと分かる、100件、500件、10,000件の壁なんかも、よろしく内部処理してくれます)。
サンプルでアプリのテンプレートも置いておきます。
実際にテストするには、FormBridgeルックアップ共存.js内の
const MASTER_APP_ID = 0; // マスタアプリの appId
const DATA_APP_ID = 0; // データアプリの appId
ここを環境に合わせて書き換える(設定画面からダウンロードして、修正後再アップロード)必要がありますので、ご注意ください。
コードはこんな感じ。
(() => {
'use strict';
// kintone REST API Client と kintone UI Component が読み込まれている前提
const MASTER_APP_ID = 0; // マスタアプリの appId
const DATA_APP_ID = 0; // データアプリの appId
kintone.events.on('app.record.index.show', (event) => {
const buttonId = 'lookup-button';
const buttonText = 'FormBridge申請データルックアップ処理';
// ボタンを設置する
const setupButton = () => {
if (document.getElementById(buttonId)) return;
const button = new Kuc.Button({
text: buttonText,
type: 'submit',
id: buttonId,
visible: true,
disabled: false
});
kintone.app.getHeaderMenuSpaceElement().appendChild(button);
button.addEventListener('click', handleButtonClick);
};
// ボタンが押されたときの処理
const handleButtonClick = async () => {
const spinner = new Kuc.Spinner({ text: '処理中...' });
spinner.open();
try {
const client = new KintoneRestAPIClient();
// データアプリの対象レコードを取得
const targetRecords = await fetchTargetRecords(client);
// マスタアプリの検索文字列を取得
const masterRecords = await fetchMasterRecords(client);
// 更新対象レコードをフィルタリング
const recordsToUpdate = buildUpdateRecords(targetRecords, masterRecords);
// レコードを一括更新
if (recordsToUpdate.length > 0) {
await client.record.updateAllRecords({
app: DATA_APP_ID,
records: recordsToUpdate
});
}
window.alert('作業を終了しました。');
spinner.close();
location.reload();
} catch (error) {
console.error('エラーが発生しました:', error);
window.alert(`エラーが発生しました:${error}`);
spinner.close();
}
};
// 対象レコードを取得する関数
const fetchTargetRecords = async (client) => {
return await client.record.getAllRecordsWithCursor({
app: DATA_APP_ID,
query: 'ルックアップ = "" and FormBridgeからのルックアップ != ""',
fields: ['$id', 'FormBridgeからのルックアップ']
});
};
// マスタの検索文字列を取得する関数
const fetchMasterRecords = async (client) => {
return await client.record.getAllRecordsWithCursor({
app: MASTER_APP_ID,
fields: ['検索文字列']
});
};
// 更新対象レコードを生成する関数
const buildUpdateRecords = (targetRecords, masterRecords) => {
const masterLookup = new Set(masterRecords.map((record) => record.検索文字列.value));
return targetRecords
.map((record) => {
if (masterLookup.has(record['FormBridgeからのルックアップ'].value)) {
return {
id: record.$id.value,
record: {
ルックアップ: { value: record['FormBridgeからのルックアップ'].value }
}
};
}
return null;
})
.filter((record) => record !== null);
};
setupButton();
});
})();
一覧表でボタンを押すだけで、梅コースと同じような作業をやってくれます。ボタン一発でできることから、梅コースより担当者が楽そうです。
ただ、カスタマイズなので、今後のアプリの設計変更等の際には気を付ける必要があります。それでも、「ルックアップ」フィールドにデータを適用すると「ほかのフィールドをコピー」も自動的に反映してくれるっていう仕組みは健在なので、カスタマイズで取り扱うフィールドの数は必要最低限で済みますから、かなりシンプルです。
【松コース】gusuku CustomineのJobRunnner機能を使う
これが使えるなら最も手っ取り早くて確実です。
FormBridgeからデータをkintoneに登録したときに、JobRunnnerを使ってkintoneのルックアップを更新するやり方です。
残念ながら、自分の環境ではJobRunnerが使えないんですが、このやり方なら、CSVをエクスポートする手間もボタン押す手間もないので、「作業忘れ」がなくなります。
他のwebhookをトリガーにイベント実行できるサービスを使ってもいいんですが、gusuku Customineだと知見も集まってるし楽ちんかな?
そういちろうさんが、実際にnoteでアウトプットしてくださってます。
さいごに
こんな感じで、kintoneやToyokumo kintoneAppで課題が生じても、いろんな方法で解決していくことが可能です。考える過程が「楽しい♪」って思えるようになれば、きっと、これからの業務改善がモリモリはかどります!
今回のアドベントカレンダーもそうですが、kintone界隈の人って、色んな経験や知見を惜しみなくアウトプットしてくれてます。ぜひ、色んな知識を手に入れて、業務改善を楽しんでください♪