はじめに
今回のTipsは、顧客ごとの自動採番に続いて、サンプルアプリ「営業支援パック」の顧客管理アプリを利用します。
顧客管理アプリには、関連レコード一覧が設定されており、同パック内の案件管理アプリと紐付いています。
そのため、顧客管理アプリ内で、その顧客に関連した案件情報が参照できます。
概要
アプリ内に配置されたテーブルの値は集計が可能ですが、関連レコード一覧の項目の集計は、標準機能ではできません。
そこでカスタマイズによって、関連レコード一覧の項目の集計を行います。
さらに、すべての関連レコードを集計するのではなく、「ある条件に合うもの」のみを集計します。
今回は、「Aプランを提案」した案件の、「合計費用」項目の値を集計します。
これでもう、参照元のアプリまで、集計結果を確認しに行く必要はありませんね!
表示するフィールドの設定
「顧客管理アプリの設定 > フォーム > 関連レコードフィールド[案件一覧]の設定 > 表示するフィールド」
において、顧客管理アプリに表示する、関連レコードのフィールドの項目と順序を設定します。
そして、集計結果の表示領域として、スペースパーツを案件一覧パーツの下部に配置します。
要素IDは、「totalAmount」とします。
また、関連レコード一覧の合計費用の位置に合うよう、任意の幅のスペースパーツと、「Aプラン小計」と記載したラベルパーツも併せて配置します。
サンプルコード
サンプルコードのポイント
関連レコードの仕組みを理解する
関連レコード一覧フィールドは、参照したいアプリの中で条件に一致したレコードを表示しているため、
現在表示しているレコード詳細画面自体には情報を持っていません。
そのため、関連レコード一覧フィールドに表示されている情報を取得するためには、
レコードを取得する kintone REST API を使用し、
関連レコード一覧フィールドの「表示するレコードの条件」を参考にして、レコードを取得する必要があります。
関連レコード一覧フィールドの「表示するレコードの条件」は、レコード取得 API 実行時の query パラメータを記載する際に利用します。
例えば、関連レコード一覧画面に相当するレコードを取得したい場合は、以下のようなクエリを記載します。
クエリのポイント
本記事では、関連レコード一覧フィールドに表示されているレコードの中から、さらに「A プランを提案した案件」に絞り込んでレコードを取得します。
そのため、先程記載したクエリに「A プラン」のみ取得できるようなクエリを書き足すと、以下のようなクエリが書けます。
集計の条件としている「提案プラン」はドロップダウンフィールドを用いているため、in句で検索します。
詳細は、こちらの記事をご確認ください。
注意事項
- 本記事のサンプルコードでは、100件を超えるレコードの取得ができません。
- 100件以上500件以下のレコードを取得する場合は、「query」パラメータでオプションを使用してください。
- 500件超のレコードを取得する場合は、「offset の制限値を考慮したレコード一括取得について」をご確認ください。
- 関連レコード一覧フィールドに一度に表示する最大レコード数にかかわらず、条件に該当するすべてのレコードを集計対象とします。
デモ環境
※デモ環境についての説明はこちら
変更履歴
- 2018/12/12
- 現在提供されているサンプルアプリに対応
- 同期リクエストから非同期リクエストへコードを変更
このTipsは、2018年12月版kintoneで確認したものになります。
あまちゃん初心者の青山です。
ずーっと見ていてもうまくできなくて嘆いています。
ご質問が2点あります。
1.顧客情報レコード番号のフィールドは必ず数値である必要があるか否か。
2.条件は含まず単にレコードの集計をしたい場合に下記コードで良いか。
です。
ちょっとずつは理解しているですが、アリさんのランチくらいしか理解できていません。
どなたか、教えていただけたら幸いです。
================================
(function() {
"use strict";
//レコードの編集、詳細画面で適用する
var events = [
'app.record.detail.show',
'app.record.edit.show'
]
kintone.events.on(events, function(event) {
var record = event.record;
var client_rid = event.recordId;
var related = kintone.app.getRelatedRecordsTargetAppId('関連レコード一覧');
var offset = 0;
var loop_end_flg = false;
var records = new Array();
while(!loop_end_flg){
var query = '数値フィールドで構成された番号="' + client_rid +
'" limit 100 offset ' + offset;
query = encodeURIComponent(query);
var appUrl = kintone.api.url('/k/v1/records') + '?app='+ related + '&query=' + query;
// 同期リクエストを行う
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", appUrl, false);
xmlHttp.setRequestHeader('X-Requested-With','XMLHttpRequest');
xmlHttp.send(null);
//取得したレコードをArrayに格納
var resp_data = JSON.parse(xmlHttp.responseText);
if(resp_data.records.length > 0){
for(var i = 0; resp_data.records.length > i; i++){
records.push(resp_data.records[i]);
}
offset += resp_data.records.length;
}else{
loop_end_flg = true;
}
}
var amount = 0;
for (var i = 0; i < records.length; i++) {
amount = amount + parseFloat(records[i].数値フィールド.value);
}
var divTotalAmount = document.createElement('div');
divTotalAmount.style.fontWeight = 'bold';
divTotalAmount.style.textAlign = 'right';
divTotalAmount.style.fontSize = 12;
var wString = String(amount.toFixed(0).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,'));
divTotalAmount.innerHTML = "\\" + wString + "-";
kintone.app.record.getSpaceElement("TotalAmount").appendChild(divTotalAmount);
return event;
});
})();
青山様、ご質問ありがとうございます。遅くなりまして恐縮ですが、
以下返信させて頂きます。
> 1.顧客情報レコード番号のフィールドは必ず数値である必要があるか否か。
顧客情報レコード番号は、案件情報アプリが保有する、その案件に関連付け
られた顧客情報アプリのレコード番号を取得しておりますが、特に数値である
必要はありません。アプリコードが設定されたアプリなどは文字列となります。
https://help.cybozu.com/ja/k/user/form_parts.html#parts_recordnum
> 2.条件は含まず単にレコードの集計をしたい場合に下記コードで良いか。
> var query = '数値フィールドで構成された番号="' + client_rid +
> '" limit 100 offset ' + offset;
案件情報アプリに、フィールドコードとして正しく「数値フィールドで構成
された番号」が設定され、それが顧客情報アプリのレコード番号を意味する
ものであれば、問題ないと思います。
「うまくできていない」というのが、どのような内容なのか(望んだ結果と
違う、エラーがでるなど)もう少し詳しい状況を教えて頂いてもよろしいで
しょうか?、よろしくお願い致します。
佐藤さま
ご丁寧にありがとうございます。お返事遅くなり申し訳ございません。
現状、営業支援(SFA)パックを利用してテストしておりますが、前の記事にある自動採番はつけずに
・企業番号(文字列)
aa-01のようなテキストを入力
フィールドコードは「企業番号」
・顧客情報レコード番号(数値)
任意の数値で案件情報にルックアップ参照させて反映
フィールドコードはどちらのアプリも「顧客情報レコード番号」
上記二通りでテストしております。
17行目の
var query = '顧客情報レコード番号="' + client_rid +
'" and ドロップダウン not in ("受注")' +
' limit 100 offset ' + offset;
の'顧客情報レコード番号="'部分だけを入れ替えて、他の条件はそのままで試しました。
スペースパーツ要素ID[TotalAmount]には、結果何も反映されない状態です。
公開いただいているソースをそのままで上記部分のみ入れ替えてjsを顧客情報アプリに入れてみました。
作業は、平成28年5月20日時点での状態です。
目的と致しましては、他のアプリで関連レコード一覧んで単位や数値を参照している連携したアプリが多く、その合計値を参照できるようにしたいのですが、
関連付けるフィールドコードが自動採番でなく、文字入力や数値で参照している場合があるため、テストしております。
js実装のタイミングや、データ登録のタイミングで反映されないのか、難しくなってきてまして。
シンプルに関連レコードの集計値を上記のように、プルダウンや、期間(日付)を指定して参照できるよう、努力しているところです。
公開されているソースでがんばってみたのですが、行き詰ってしまいました((+_+))
Keizaburou Aoyama様
通知に気付くことができず、返信が大変遅くなっていまい申し訳ありません。
> スペースパーツ要素ID[TotalAmount]には、結果何も反映されない状態です。
ということですと、構文上のエラーなどが発生しているというより、ロジックとして、希望する動作になっていない
可能性がありそうです。
> var query = '顧客情報レコード番号="' + client_rid + '" and ドロップダウン not in ("受注") limit 100 offset ' + offset;
> の'顧客情報レコード番号="'部分だけを入れ替えて、他の条件はそのままで試しました。
とのことですが、これは追加した「企業番号」または「顧客情報レコード番号」を使用されたということですよね?
query文中の、client_rid は、レコード詳細を参照している時に、eventオブジェクトのプロパティ recordId(数値)
を取得(この場合は参照している顧客情報)していますので、追加した項目とは無関係になります。
もし、登録している企業番号などの情報で検索されたいのであれば、query文を組み立てる前に、
var companyNumber = record['企業番号'].value;
などとして、この変数をquery文で使用するなどの対応が必要だと思います。
ところで、Aoyama様さえよろしければ、Facebookで友だち申請頂いてもよろしいでしょうか?
どうもこのコメント欄画面などが貼れず、説明がもどかしいですので、FBのノートを共有させて頂くなど別の方法を
考えたいと思いますので。よろしければということで、ご検討下さいませ。
https://www.facebook.com/kojisato2002
佐藤さま
丁寧にありがとうございます。
とても参考になります。
なんとか実装できました。
が、動いたり動かなかったりなので
>var companyNumber = record['企業番号'].value;
でも試していきたいと思います。
ありがとうございます。
おそらくみなさんもだと思うのですが、集計値をフィールドに返す、や、日付フィールドを指定してその期間内だけで集計する、っていうものが
あれば便利だなあーと、再度挑戦中です。
標準機能で欲しいところですね!
期間内集計は、まだ実装出来ていませんが、FB友達申請させていただきました!
ありがとうございます!
また、お世話をおかけいたしましてすいません!涙
松永 直人さん
ご質問ありがとうございます。
エラー「Cannot read property 'length' of undefined」の発生原因は次↓のではないかと思います。
resp_dataにデータが入っていない(レスポンスが帰ってこない)為、resp_dataのlengthが見つけないからです。
なぜresp_dataにデータが入っていないというと、queryのところで「顧客情報レコード番号」を指定していますが、
現在のアプリストア中の顧客情報アプリと案件情報アプリのフィールドが変わって、案件情報アプリ中の「顧客情報レコード番号」というフィールドがなくなりました。
なのでqueryに別のフィールドを指定しなおすと、動けると思います。
ちなみに、自分が、顧客名=会社名のように書き直して動いていることを確認しました。
var client_name = record["会社名"]["value"];
var related = kintone.app.getRelatedRecordsTargetAppId('関連レコード一覧');
var offset = 0;
var loop_end_flg = false;
var records = new Array();
while(!loop_end_flg){
var query = '顧客名="' + client_name
Qiuxiang Su 様
早速の書き込みありがとうございます。
ご提示していただいているとおり変更しましたがうまく動きません。
var client_name = record["会社名"]["value"]; の行がエラーとなってしまいます。
大変お手数ですが今回変更した部分を含めて全行のソースコードを見せていただけないでしょうか?
宜しくお願いします。
松永 直人様
フォーム設定で「会社名」フィールドのフィールドコードも「会社名」に変更しましたか?
案件情報アプリの「顧客名」も同じくフィールドコードを「顧客名」に設定する必要があります。
説明不足で申し訳ありませんでした<m(__)m>。
次はソースコードになります。
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー‐
(function() {
"use strict";
//レコードの編集、詳細画面で適用する
var events = [
'app.record.detail.show',
'app.record.edit.show'
]
kintone.events.on(events, function(event) {
var record = event.record;
var client_name = record["会社名"]["value"];
var related = kintone.app.getRelatedRecordsTargetAppId('関連レコード一覧');
var offset = 0;
var loop_end_flg = false;
var records = new Array();
while(!loop_end_flg){
var query = '顧客名="' + client_name +
'" and ドロップダウン not in ("受注")' +
' limit 100 offset ' + offset;
query = encodeURIComponent(query);
var appUrl = kintone.api.url('/k/v1/records') + '?app='+ related + '&query=' + query;
// 同期リクエストを行う
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", appUrl, false);
xmlHttp.setRequestHeader('X-Requested-With','XMLHttpRequest');
xmlHttp.send();
//取得したレコードをArrayに格納
var resp_data = JSON.parse(xmlHttp.responseText);
if(resp_data.records.length > 0){
for(var i = 0; resp_data.records.length > i; i++){
records.push(resp_data.records[i]);
}
offset += resp_data.records.length;
}else{
loop_end_flg = true;
}
}
var amount = 0;
for (var i = 0; i < records.length; i++) {
amount = amount + parseFloat(records[i].数値.value);
}
var divTotalAmount = document.createElement('div');
divTotalAmount.style.fontWeight = 'bold';
divTotalAmount.style.textAlign = 'right';
divTotalAmount.style.fontSize = 12;
var wString = String(amount.toFixed(0).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,'));
divTotalAmount.innerHTML = "¥" + wString + "-";
kintone.app.record.getSpaceElement("TotalAmount").appendChild(divTotalAmount);
return event;
});
})();
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
Qiuxiang Su 様
早速の返信書き込みありがとうございます。
ご提示していただいているとおりに変更し、無事動きました。
これを応用して他のアプリにも活用させていただきます。
この度は誠にありがとうございました。
松永 直人様
動いてよかったです。
実は一つ訂正させていただきたいところがあります。
「顧客情報レコード番号」はなくなったわけではなく、この前の記事「顧客ごとの自動採番」で読者に追加していただくものです。
間違いまして申し訳ありませんでした。
Qiuxiang Su 様
訂正の件、ご丁寧にありがとうございます。
ソースコードの中身を完全に理解していなくても、やりたいことが実現でき不思議な感じです。
まだまだ不安を抱えていますが、徐々に理解を深めていきたいと思います。
この度は誠にありがとうございました。
初めまして。
超初心者で大変恐縮なのですが、質問させてください。
顧客情報アプリではなく当方が作成したアプリで関連レコードの集計を行いたいのですが、
本サンプルコードのどの部分を修正するか分からず、集計が行なえません。。
お手数ですが、どなたかご教授いただけないでしょうか。
どうぞ宜しくお願いいたします。
お世話になっております。
cybozu developer network運営事務局です。
12、17、18、44、53行目に記載されているフィールドコードや要素IDを、
利用するアプリに合わせて変えていただければよろしいかと存じます。
なお、記事内容外の実現方法のご相談については、コミュニティをご活用頂けますと幸いです。
cybozu developer network運営事務局 さま
早速ご返信いただきありがとうございます!
ご教示いただいた箇所の修正を試してみます。
以後こういった質問はコミュニティのほうへ投稿させていただきます。
ありがとうございました。
お世話になっております。
初心者で大変恐縮です。
var query = '顧客情報レコード番号="' + client_rid + ⇒この行の意味を教えていただけますか?
'" and ドロップダウン not in ("受注")' +
' limit 100 offset ' + offset;
自社のに応用したいですが、なかなか理解ができず、困っております。
なにかアドバイスいただけると幸いです。ぜひよろしくお願い致します。
玲香様
お世話になっております。
cybozu developer network 運営事務局です。
> var query = '顧客情報レコード番号="' + client_rid +
こちらはREST APIでGETするレコードを絞り込むためにクエリを記述しております。
今回の場合ですと、顧客情報アプリのレコード番号(= 顧客ごとに一意の値)を案件情報アプリの該当レコードにルックアップで紐づけているため、
顧客情報アプリのレコードIDで絞り込むことで、同じ顧客の案件情報のみが取得できます。
いつも大変お世話になっております。
kintone api()を用いた実装ですとコードのご提供は可能でしょうか?初心者のため、どこをどう変えればよろしいか彷徨っておりまして、それともコミュニティに投稿したほうがよろしいでしょうか?なにかアドバイスいただけると幸いです。どうぞよろしくお願い致します。
サラ様
基本的に、メインのシナリオ以外のコードの提供は行っておりませんので、技術的なご質問はコミュニティでお願いします。
kintone.api()そのものの解説であれば、以下の記事が参考になると思います。
kintone.apiにゲストスペースでも使える正しいパスを指定する
https://developer.cybozu.io/hc/ja/articles/202707864
なお、kintone.api()を使いたいのかの意図をわかりかねましたので、
たとえば、Promiseを使った書き方をしたい、等であれば、
当サイトにも既存の記事がいくつかありますので、そちらを参考にして試行した上でコミュニティで質問ください。
この度、kintone契約をさせていただきました。
どうしても合計値の表示ができなく質問させていただきます。
こちらのサンプルで以下の(1)、(2)のところを超初心者なりに(3)、(4)のように書き換えました。
というのも、関連レコードの相手側テーブルの参照先のフィールドAと関連レコードを設定しているテーブルのフィールドBの一致したもののレコードをとり、関連レコードの相手側テーブルのフィールドCの値の合計値を出したいだけなのです。
フォームではもちろん合計値以外は表示されております。
(3)var client_field = event.record['フィールドコード'][value];
(4)var query = '相手側テーブルの参照先のフィールドコード ="' + client_field +
' limit 100 offset ' + offset;
-----------------
kintone.events.on(events, function(event) {
var record = event.record;
var client_rid = event.recordId;(1)
var related = kintone.app.getRelatedRecordsTargetAppId('関連レコード一覧');
var offset = 0;
var loop_end_flg = false;
var records = new Array();
while(!loop_end_flg){
var query = '顧客情報レコード番号="' + client_rid +
'" and ドロップダウン not in ("受注")' +
' limit 100 offset ' + offset;(2)
query = encodeURIComponent(query);
var appUrl = kintone.api.url('/k/v1/records') + '?app='+ related + '&query=' + query;
// 同期リクエストを行う
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", appUrl, false);
xmlHttp.setRequestHeader('X-Requested-With','XMLHttpRequest');
xmlHttp.send(null);
//取得したレコードをArrayに格納
var resp_data = JSON.parse(xmlHttp.responseText);
if(resp_data.records.length > 0){
for(var i = 0; resp_data.records.length > i; i++){
records.push(resp_data.records[i]);
}
offset += resp_data.records.length;
}else{
loop_end_flg = true;
}
}
(1)のまま(2)の'顧客情報レコード番号='を'相手側テーブルの参照先のフィールドコード'にすると、関連レコードを設定しているテーブルのレコードIDと同じ相手側テーブルのフィールドAの値(1レコード)は表示されます。
基本的なことを理解しないまま質問をしており恐縮ですが、何かアドバイスをよろしくお願い申し上げます。
追記:
'" and ドロップダウン not in ("受注")' + などの条件は必要ありませんので書いてもおりません。
りょうすけ 様
お世話になっております。developer network 事務局です。
こちらの記事は作成日時が古く、現在だともっとスマートにできる方法があります。
こちらのナレッジノートに同様の仕組みを現在のやり方で行ったコードがありますので、ぜひこちらをご参照ください。
https://developer.cybozu.io/hc/ja/community/posts/360017851006
また、こちらのコメント欄では記事内のシナリオ/コードへの質問のみ受け付けております。
コード修正による技術的な質問は、コミュニティで質問いただけると幸いです。
よろしくお願いいたします。
デモ環境:
(スペース)https://dev-demo.cybozu.com/k/#/space/6/thread/6
配下にアプリが掲載されたのですが、アプリの説明にあるこの記事のリンクが間違っています。
(誤)https://developer.cybozu.io/hc/ja/articles/360020415311
(正)https://developer.cybozu.io/hc/ja/articles/203030394
大田様 いつもお世話になっております。
ご指摘をありがとうございます。デモ環境のアプリの本文におけるこの記事へのリンクを修正いたしました。
みなさま
はじめまして。
最近キントーンを知り導入しようかとお試しの1ヶ月無料アカウントで色々と顧客管理・商談管理などの仕組みを模索しているものですが、どうしても関連レコードの売上データを集計する必要が出てまいりました。
テクニカルサポートの方からこちらのスレをご紹介いただいたのですが、プログラムなど全くの素人のため、よく分かっておりません。
とりあえずこちらのテストプログラムを試してみたいのですが、うんともすんとも動きません。
(動いているのかもしれませんが、合計値が返ってきません。)
既に昔のスレの様ですので、生きているのかどうかもわからないのですが、現状のキントーンのサンプルアプリ「営業支援パック」でもこのプログラムは
動くのでしょうか。
もし、可能でしたらサンプルアプリ上の「提案プラン」など条件に関わらず全ての「合計費用」の合計を返す方法を教えてください。
他の方のやり取りも読みましたが、テストプログラムさえ動かない状況ですので全く分かりませんでした。
お手数ですが、どうぞ宜しくお願い致します。
林 威智郎 様
お世話になっております。
cybozu developer network 運営局です。
cybozu developer network には、JavaScript と kintone カスタマイズを学習できるコンテンツを用意しておりますので、
ぜひこちらをご活用ください。
こちらの記事ですが、現時点の「営業支援パック」の「顧客管理」アプリで、動作することを確認しております。
以下の点についてご教示いただけないでしょうか?
出ていたら、そのエラーメッセージをご教示ください。
開発者ツールの開き方はこちらの記事をご参照ください。
また、こちらは記事に対するコメント欄になっているため、コメントされたことの通知は、記事をフォローしている人にしか届きません。
コミュニティへの投稿だと、いろんな方の目に触れるため回答が得られやすいかと思います。
ぜひコミュニティをご活用ください。
cybozu developer network 運営局
ご担当者さま
この度はお世話になります。
初歩的なことで申し訳ございません。
取り急ぎ以下の点について状況をお伝えいたします。
⇒支援パックに含まれている「顧客管理」「「案件管理」「活動履歴」はそのまま入れ、それぞれ動作確認済みです。その内、カスタマイズを適用したアプリは「顧客管理」アプリです。
⇒開発者ツール自体知りませんでした。ここにエラーが出るのですね。ちなみにエラーは
download.do:34 Uncaught SyntaxError: Invalid or unexpected token
show#record=20&l.view=2031&l.q&l.sort_0=f2012&l.order_0=DESC&l.next=19&l.prev=0:1 Unchecked runtime.lastError: The message port closed before a response was received.
となっています。
以上、どうぞ宜しくお願いいたします。
I.Hayashi 様
お世話になっております。cybozu developer network です。
> 開発者ツール自体知りませんでした。ここにエラーが出るのですね。
ぜひ、こちらの記事 でデバッグの仕方を学んでおくと、エラー時に対処できるので役に立つかと思います。
ちなみに、download.do:34 の部分がリンクになっているかと思うのですが、ここをクリックするとエラーになっている部分を確認できます。
エラーメッセージありがとうございます。
「Uncaught SyntaxError: Invalid or unexpected token」は、「何か書き方が間違っています」というエラーです。
この記事のソースコードに対して、手を加えていますでしょうか?
もし手を加えていたら、修正後のソースコード全体を教えて下さい。
cybozu developer network
ご担当者さま
早々にお返事いただき、ありがとうございました。
この記事に関して何も触ってはいませんが、教えていただきましたdownload.do:34 の部分のリンクへ飛ぶとプログラムが一部文字化けしている様です。
カスタマイズの手順として、ここの記事のプログラムをコピーしてWin7のメモ帳に貼り付け、それを拡張子「.js」で保存し直し、「顧客管理」アプリの
設定「JavaScript/CSSでカスタマイズ」から「アップロードして追加」を行いました。
メモ帳に貼り付けた段階では文字化けはしていませんが、どこかの相性などで文字化けしたのでしょうか。
他の貼り付け方法がありましたらご教示ください。