・料金テーブルアプリ
フィールド ~ クラス、単価、個数、料金、特単価、特個数、特料金
(通常~ 単価、個数、料金 特殊~ 特単価、特個数、特料金)
・請求アプリ
フィールド ~ クラス、チェックボックス(通常・特殊)、単価、個数、請求額
請求アプリのクラス・チェックボックスの値から、料金テーブルのそれぞれ単価(特単価)と、通常の際は個数 > x の場合は料金、特殊の際は個数 > x の場合は特料金を表引きし請求額に値をセットしたい。
初心者なので、単にルックアップでやろうとしましたが、複数条件による表引きができません。プラグインではお金がかかるのでJSを自作するしかありません。
(function () {
“use strict”;
kintone.events.on([‘app.record.create.submit’,‘app.record.edit.submit’], function(event){
return kintone.api(‘/k/v1/record’,‘PUT’, {
app: アプリNo, //料金テーブル
updateKey: {field: “クラス”,value: event.record.クラス.value
},
record: {単価: {value: field: “単価”
}
}
}).then(function(){
return event;
});
});
})();
こんな感じをカスタマイズすればできそうですが、、、
JSを勉強したいのでご教示いただければ幸いです。
JavaScriptを使用しないのであれば、ルックアップから「単価」「特単価」の両方をフィールドにコピーするようにし、請求アプリの「請求額」フィールドにkintone標準機能の計算式適用(IF文を使い、チェックボックスの値に応じて単価か特単価)で良いと思います。
JavaScriptを使う場合、以下のようなイメージになると思います(クラスは一意の値である前提です。クラスの一致する複数のレコードから選択していく場合は、やはりkintone標準機能の計算式を使用した方が手軽だと存じます)。
(function() {
'use strict';
var classField = 'クラス';// 請求アプリの「クラス」フィールドコード
var checkboxField = 'チェックボックス';// 請求アプリの「チェックボックス」フィールドコード
var numberField = '個数';// 請求アプリの「個数」フィールドコード
var priceAppId = ;// 料金テーブルアプリのアプリID
var x = ;// 個数 > x の値
var events = [];
[classField, checkboxField, numberField].forEach(function(field) {
events.push('app.record.create.change.' + field, 'app.record.edit.change.' + field);
});
kintone.events.on(events, function(event) {
var record = event.record;
if (!record[classField].value || !record[checkboxField].value.length) return event;
var getRecords = {
app: priceAppId,
query: 'クラス = \"' + record[classField].value + '\"'
};
kintone.api(kintone.api.url('/k/v1/records', true), 'GET', getRecords, function(resp) {
var recordData = kintone.app.record.get(), rec = recordData.record;
var respRecord = resp.records[0];
var unitPrice = rec[checkboxField].value.includes('通常') ? respRecord['料金'].value: respRecord['特料金'].value;
if (rec[numberField].value > x) rec['請求額'].value = unitPrice;
kintone.app.record.set(recordData);
}, function(error) {
alert(JSON.stringify(error));
});
return event;
});
})();
mls-hashimoto さま
JSの勉強をしたいので、上記スクリプトを手直しし実行したところ、料金テーブルからの単価・特約単価は正しく表引出来てますが、ここでスクリプトが停止します。
TypeError: Cannot read properties of undefined (reading ‘条件’)
どうやらこれがエラーの原因のようですが対処の仕方が解りません。
(チェックボックスからラジオボタンに変更しています)
ご教示下されば幸いです。宜しくお願い致します。
FURUNO.T さま
(実のところ今朝スクリプトのミスに気付いて変更しました。32行目のkintone.app.record.getの後に()が必要です。申し訳ありません)
使用していた「includes」はチェックボックス(配列)に含まれるかの判定に使用するため、ラジオボタンであればこちらに変更して下さい。
var unitPrice = rec[checkboxField].value == '通常' ? respRecord['単価'].value: respRecord['特約単価'].value;
24行目も
if (!record[classField].value) return event;
だけで問題ありません(ラジオボタンであれば変更しなくても問題ありません)。
また気になったことが2点あります。
①イベントにsubmitが追加されているようですが、submitイベントでAPIを使ったスクリプトを動作させるのであればPromiseまたはkintone.Promiseを使用する必要があります(スクリプトの処理完了より先にkintoneの保存完了が起きるためです。またchangeイベントではkintone.Promiseを使えず、submitイベントではkintone.app.record.get()等が使えないのでエラーになります)。
https://developer.cybozu.io/hc/ja/articles/360023047852
https://developer.cybozu.io/hc/ja/articles/900004201403-kintone-Promise
②8行目のxに「日数」が代入されていますが、日数というフィールドの値のことでしょうか(x = 5 の場合 個数 > 5というイメージでいました)。
その場合であれば、36行目のxを
rec[x].value
と変更する等で対応して下さい。
mls-hashimoto さま
素早いご対応、ありがとうございます。
確かに、submitイベントは不要で、フィールドイベントだけでした。
クラスはルックアップからのコピーフィールドです。ラジオボタンは、通常・特約の二択です。
このクラスとラジオボタンの値から請求アプリの単価は、通常選択時は料金テーブルの単価を、特約選択時は特約単価の値を表引きしたいです。更に請求アプリの日数が料金テーブルの日数を超えると通常選択時は料金テーブルのMというフィールド値を、特約選択時は特約Mというフィールド値をそれぞれ請求アプリの請求額に表引きさせたいです。
上記mls-hashimoto さまからのご指摘いただき手直しし実行したエラー結果です。ご教示宜しくお願い致します。
FURUNO.T さま
先のコメントの1行目にあるように27行目のkintone.app.record.getの後に()が必要です。当初の記載ミスです。申し訳ありません。
mls-hashimoto さま
承知いたしました。() を付け足して、フィールドイベントを
var events = [
‘app.record.create.change.クラス’,
‘app.record.create.change.条件’, //デフォルトは通常
‘app.record.create.change.日数’,
‘app.record.edit.change.クラス’,
‘app.record.edit.change.条件’, //デフォルトは通常
‘app.record.edit.change.日数’
];
に変更し実行するとエラーは出ませんが、単価及び請求額に表引きされません。
クラスがルックアップからのコピー先というのが原因でしょうか?
宜しくお願い致します。
FURUNO.T さま
こちらも見落としていました。6行目で宣言しているnumberFieldと8行目で宣言しているxが最終的に同じフィールドを参照しているようです。個数 > x の場合に動くように作ったので、31行目のif文の括弧を削除すれば動くはずです。
JSEdit上のものはエラーというよりプログラミングの書き方の推奨のようなものです。あまり気にしなくて問題ありません(「rec[‘M’]」と「rec.M」で同じ意味であるものの、後者の記法を推奨しているようです。詳細はブラケット記法、ドット記法等でお調べいただくと出てきますが、慣れてからで問題ありません)。
イベントは12~14行目で全く同じものを宣言しているので、追記していただかなくても問題ありません。
mls-hashimoto さま
イベントの書き方にも色々な方法があるのですね。初心者故勉強します。
上の宣言は、var events = []; あるいは削除で良いのでしょうか?
また、IFの()を外した ↓ ところ × になりますが良いのでしょうか?
ラジオボタンの値が特約の場合の請求額への表引きがないように見えますが・・・
ご教示宜しくお願い致します。
FURUNO.T さま
言葉足らずでした。38行目は
rec['M'].value = unitPrice;
で問題ありません。
特約の場合の単価ですが、
var unitPrice = rec[checkboxField].value == '通常' ? respRecord['単価'].value: respRecord['特約単価'].value;
の部分で変数「unitPrice」に「チェックボックスが通常なら単価、そうでないなら特約単価」を代入するようにし(三項演算子等でお調べいただければ出て来るかと思います)、そのunitPriceをrecord[‘M’].valueに代入しています。
イベントについては
var events = [];
で問題ありません。
38行目のif文を削除したため、イベント宣言の下の12~14行目からnumberFieldは削除して
[classField, checkboxField].forEach(function(field) {
events.push('app.record.create.change.' + field, 'app.record.edit.change.' + field);
});
で問題ないですね。
mls-hashimoto さま
ご教示の通り書き換えて実行したところです。31行目で赤×ですが、エラーなく保存はできます。が、単価等表引きしてくれません。引き続き宜しくお願い致します。
FURUNO.T さま
レコードの日数が料金アプリの日数を超えた場合、単価をMまたは特約Mにしたい旨を見落としておりました。申し訳ありません。30行目に
if (rec['日数'].value > respRecord['日数'].value) unitPrice = rec[checkboxField].value == '通常' ? respRecord['M'].value: respRecord['特約M'].value;
こちらを追加して下さい。
また、31行目の「rec[‘M’].value = unitPrice」は、「現在開いているレコードのフィールド『M』に料金テーブルから取得した単価を代入する」という記述になっているので、恐らくは「rec[‘請求額’].value = unitPrice」が正しいのではないかと思われます。
mls-hashimoto さま
ありがとうございます。上記JSとrec[‘請求額’].value = unitPrice に手直しし正常に動作いたしました!
実は請求appの日数は、開始日・終了日から日数を計算しこの日数と料金TBLの日数と比較して、更に通常か特約かで請求app>料金TBLの場合はM(特約M)料金を、請求app<=料金TBLの場合は請求app×単価(特単価)をそれぞれ請求額に表引きという風に下記のようにアレンジしてみましたが、うまく行きません。
また、予定日数を標準搭載の式ではなく、学習のためと手入力を可能としたいのでJSでやろうと調べると、初心者故難解です。
この二つをご教示いただければ幸いです。
var recordData = kintone.app.record.get(), rec = recordData.record;
var respRecord = resp.records[0];
var unitPrice = rec[checkboxField].value == '通常' ? respRecord['単価'].value: respRecord['特約単価'].value;
var mPrice = 0;
var tPrice = 0;
if (rec['日数'].value > respRecord['日数'].value) mPrice = rec[checkboxField].value == '通常' ? respRecord['M'].value: respRecord['特約M'].value;
if (rec['日数'].value <= respRecord['日数'].value) tPrice = mPrice * respRecord['日数'].value;
rec['単価'].value = unitPrice;
rec['利用料金'].value = mPrice;
rec['利用料金'].value = tPrice;
FURUNO.T さま
おそらく以下のようなイメージでしょうか。
var recordData = kintone.app.record.get(), rec = recordData.record;
var respRecord = resp.records[0];
var unitPrice = rec[checkboxField].value == '通常' ? respRecord['単価'].value: respRecord['特約単価'].value;
rec['単価'].value = unitPrice;
if (rec['日数'].value > respRecord['日数'].value) {
rec['利用料金'].value = rec[checkboxField].value == '通常' ? respRecord['M'].value: respRecord['特約M'].value;
} else {
rec['利用料金'].value = unitPrice * respRecord['日数'].value;
}
また日数を求める計算式はDay.js等のライブラリを使用すると簡単に求められます。
https://unpkg.com/dayjs
https://unpkg.com/dayjs@1.7.7/locale/ja.js
上2つを「JavaScript / CSSでカスタマイズ」の「URL指定で追加」で追加し、
(function() {
'use strict';
kintone.events.on([
'app.record.create.change.開始日', 'app.record.edit.change.開始日',
'app.record.create.change.終了日', 'app.record.edit.change.終了日',
], function(event) {
var record = event.record;
if (!record['開始日'].value || !record['終了日'].value) {
record['日数'].value = '';
} else {
record['日数'].value = dayjs(record['終了日'].value).diff(record['開始日'].value, 'day');
}
return event;
});
})();
を追加すれば日数を求められます…が、個人的にはおすすめしません(今後更にカスタマイズをしていく時に弊害になる可能性があります。特にREST APIでレコードの操作をしていくとなると、何かと不便になります。kintoneの標準機能計算で簡単に実装できることはそちらで済ませた方が個人的には良いと思います)。
mls-hashimoto さま
いつもありがとうございます。
日付計算は入力の手間を考えると、開始日 + 請求appの(日数は紛らわしいので)予定日数で終了日を求めたいと思い、ご教示くださったJSを手直しし
https://unpkg.com/dayjs
https://unpkg.com/dayjs@1.7.7/locale/ja.js
を組み込みましたが、以下でエラーでした(基本がなってない?)。
また、checkboxFieldが特約の際は、請求appの日数と料金TBLの特約日数を比較、大きければ料金TBLの特約Mを利用料金(請求額)に表引きしたいので色々と勉強しましたが、ギブでした。
kintone.api(kintone.api.url(‘/k/v1/records’, true), ‘GET’, getRecords, function(resp) {
var recordData = kintone.app.record.get(), rec = recordData.record;
var respRecord = resp.records[0];
var unitPrice = rec[checkboxField].value == ‘通常’ ? respRecord[‘単価’].value: respRecord[‘特約単価’].value;
if (!record[‘開始日’].value || !record[‘予定日数’].value) {
record[‘終了日’].value = ‘’;
} else {
record[‘終了日’].value = plus({month: numberField}); ←エラー
}
record[‘終了時刻’].value = plus({hours: 24}); //終了時刻=開始時刻 ←エラー
rec[‘単価’].value = unitPrice;
if (rec[‘予定日数’].value > respRecord[‘日数’].value) {
rec[‘利用料金’].value = rec[checkboxField].value == ‘通常’ ? respRecord[‘M’].value: respRecord[‘特約M’].value;
} else {
rec[‘利用料金’].value = unitPrice * rec[‘予定日数’].value;
}
VBA風だと IF checkboxField > ‘予定日数’ and checkboxField =’特約’ then ‘特約M’ ?
また、JSについていったい何から勉強すればよいか、初心者故チュートリアルにある「はじめよう JavaScript」を勉強しましたが、Kintoneは文法・作法が違うとか、APIとか色々ありますがどんな時にどれでコーティングしたら良いか、何を組み込みだら良いか等々、サンプルスクリプトが豊富で参考になる良いサイトをご教授いただければ幸いです(自分のレベルはVBAが中級、HTML・CSSは10数年ほど前に少しかじった程度です)。
宜しくお願い致します。
FURUNO.T さま
以下のような形でいかがでしょうか(変数を多用していたため、直観的になるよう書き換えました)
// 終了日を求める計算
if (!rec['開始日'].value) {
rec['終了日'].value = '';
} else {
rec['終了日'].value = dayjs(rec['開始日'].value).add(rec['日数'].value, 'day').format('YYYY-MM-DD');
/*
* 日を加算ではなく月を加算であれば'day'を'month'に
* 年の加算であれば'day'を'year'に
* 減算であれば.addを.subtractに
*/
}
// 予定日数に応じて利用料金を決定
if (rec['予定日数'].value > respRecord['日数'].value) {
if (rec['条件'].value == '通常') {
rec['利用料金'].value = respRecord['M'].value;
} else if (rec['条件'].value == '特約') {
rec['利用料金'].value = respRecord['特約M'].value;
}
} else {
rec['利用料金'].value = unitPrice * rec['予定日数'].value;
}
// 終了時刻を求める計算
rec['終了時刻'].value = rec['開始時刻'].value;
/*
* 終了時刻を開始時刻の数時間後に設定する場合
*
if (!rec['開始時刻'].value) {
rec['終了時刻'].value = '';
} else {
var splitTime rec['開始時刻'].value.split(':');
rec['終了時刻'].value = dayjs().hour(splitTime[0]).minute(splitTime[1]).add(*足す時間の数字*, 'hour').format('HH:mm');
}
*
*/
JavaScriptの勉強についてですが、あまり参考になるか分かりませんが私はほとんどこのコミュニティで習得しました。
(自分の勉強よりとにかく機能の実装が必要だったので)実装したいことを検索すると大抵誰かが答えを記述しているので、それをコピペして見様見真似しながら今に至っています(理解しないまま開発して、一通り実装した後にようやく理解できるようになっていました)。
個人的に一般的なJavaScriptの解説サイトはkintoneの開発をする上では不要な(使わない)情報が多いと感じているので、kintoneの開発のためのJavaScript習得であればこの場所かチュートリアルページがおすすめではあります。その上で詰まったところをその都度検索する等が一番近道ではないかと考えております。
mls-hashimoto さま
いつもの神対応に感謝申し上げます。
早速動作確認いたしましたところ、一見正常に見えますが
①条件=通常も特約も、予定日数が 3~9 までが M 料金になり、単価 × 予定日数 になりません。この数以外は②以外で正常です。
②条件=特約のとき ① に加え、予定日数 > 日数 が一日少ない数で表引きします(本来は23で特約Mのところ22で表引きしてきます。
JS勉強の件、確かにkintoneのみでの構築ですので、おっしゃる通りですね。
>自分の勉強よりとにかく機能の実装が必要だったので・・・
自分もそうです。業務改善に向けてより良いインターフェース、エラー処理等充実させたく今後とも宜しくお願い致します。
追伸です。
以下の部分がエラーと出てます。
https://unpkg.com/dayjs
https://unpkg.com/dayjs@1.7.7/locale/ja.js
を組み込んでますが、関係ありますか?
開始→出発に変更、終了→帰着に変更(時刻も)しております。