いつもお世話になっております。
サブテーブルの計算のさせ方について質問させてください。
サブテーブル内で、自動計算をさせたいと思っています。
分類が小計を選択した場合に、該当するAとB区分が同じ場合、小計を出す、という感じです。
(function() {
'use strict';
var events = [
"app.record.create.change.分類",
"app.record.edit.change.分類",
"app.record.create.change.A",
"app.record.edit.change.A",
"app.record.create.change.B",
"app.record.edit.change.B",
"app.record.create.change.数量",
"app.record.edit.change.数量",
"app.record.create.change.単価",
"app.record.edit.change.単価"
];
kintone.events.on(events, function(event) {
var record = event.record;
var row = event.changes.row;
var mainTable = event.record.テーブル.value;
var sumSyokei_tanka = 0;
if(row){
//小計の集計
if(row.value['分類'].value !== "表紙" && row.value['A'].value && row.value['B'].value){
//計算
for (var i =0; i < mainTable.length; i++) {
if(mainTable[i].value['分類'].value != "小計" && mainTable[i].value['A'].value == row.value['A'].value && mainTable[i].value['B'].value == row.value['B'].value){
if(mainTable[i].value['数量'].value && mainTable[i].value['単価'].value){
sumSyokei_tanka += Number(mainTable[i].value['数量'].value) * Number(mainTable[i].value['単価'].value);
}
}
}
//書き込み
for (var j = 0; j < mainTable.length; j++) {
if(mainTable[j].value['分類'].value == "小計" && mainTable[j].value['A'].value == row.value['A'].value && mainTable[j].value['B'].value == row.value['B'].value){
if(sumSyokei_tanka !== 0){
mainTable[j].value['単価'].value = sumSyokei_tanka;
break;
}
}
}
}
}
return event;
});
})();
ただ、分類小計で選択すると処理が走り、単価が書き換えられ、単価が書き換えられるからまた処理が走る…という、2度もループが走ることになります。
また、空白行がある場合は無限ループに陥ります。
自動でなんとか集計させたいのですが、いい方法はないでしょうか?
ご教授お願いします。
matsu様
>分類が小計を選択した場合に、該当するAとB区分が同じ場合、小計を出す
…という仕様であれば,javascriptでなくてもできそうですが,
計算フィールドや文字列(1行)の自動計算が使えないような制限はありますか?
もし,フィールドの計算でまかなえるなら,javascriptよりも管理しやすいかと思います.
また,コードではchangeイベントが発火するたびにテーブル行すべてに対して処理を行っているように見えます.
分類,単価,小計が1行内にあり,それらの自動計算で良いならchangeイベントが発火した行だけで良いように思います.
なお,想定されている自動計算のトリガーは「分類が変わったとき」になりますが,
コードでは数量や単価もchangeイベントのトリガーになっています.
これだと分類が変わって処理が走れば,処理によって単価が「変わる」ので,
当然単価のchangeイベントが走ることになります.
なので,分類が変わったとき以外でchangeイベントを発火する必要がないなら,
トリガーに含めなくて良いかと思います.
上記について,確認ください.
TO様
ご返信ありがとうございます。
>分類が小計を選択した場合に、該当するAとB区分が同じ場合、小計を出すを計算フィールドで
計算でもいけますか?
分類 A区分 B区分 数 単価 金額
明細 1 1 1 300 300
明細 1 1 2 200 400
小計 1 1 1 700 700
上記のように700円の単価を出す計算式がわかりません…
もし計算でいけるのであればそうしたいです。
>発火した行だけ対象の処理
発火以外の行を集計したいので全テーブル回しています。
>分類が変わった時だけでいいのでは?
分類が変わった時、数が変更された時、単価が変更された時、
全てのタイミングで自動で数字が変更されればと思っています。
matsu様
テーブル内に小計を用意する仕様なのですね…想定していませんでした.
テーブル外に小計用の計算フィールドを置いて,SUM関数を使うことでテーブル内データの合計が可能ですが,
テーブル内で小計できたほうが良いですか?
上記が許容できるなら,テーブルに例えば「A金額」,「B金額」のように区分別に計算するフィールドを別にすることで,
テーブル外の小計フィールドに,任意の区分における小計求めることができます.
区分が増えるのであれば大変ですが,ある程度決まっているならこういう手もあるかと思います.
許容できないのであればjavascriptになるかと思います.
重複して処理が走る問題については,数量,単価ではなく,
おそらくフィールド上で計算していると思われる「金額」をトリガーにするのが良いかと思います.
これなら,入力によって数量,単価が変われば金額が変わって処理が走りますし,
処理によって金額が変わる箇所については,changeイベントの最初にrow(changeイベントのトリガーになっている行)の分類が"小計"であれば処理せずに抜ける,というコードを加えることで,処理が重複することはなくなると思います.
(処理に金額が変わるのは小計の行のみ)
参考になれば幸いです.
TO様
分類が小計以外にも他の分類があるため、一概に区分別にSUMするというわけにはいかず、javascriptで処理させてみました。
また、テーブル内の方が見やすいという上司の意見もあります。
金額で発火できればよかったのですが、計算フィールドは発火できないみたいなんです。
金額を計算フィールドではなく、数値にしてJS処理で数値を入れ、全体の計算を金額発火の方がスマートですかね?
matsu様
>計算フィールドはchangeイベントの対象外
そうでした.これをいつも忘れてしまいます.
メンテナンス性を考えると,フォーム内でできることはフォーム内のほうが良いようには思います.
現状で問題になっている重複処理と無限ループについて,
無限ループは空白行で起こる,とのことですが,具体的にはどのような状態で起きていますか?
単価,数量が空欄の場合の対応はされていますし,空白行がどのような形で発生するのかわからないので,
どこがループになっているのか把握できていません.
上記について,可能であれば教えてください.
TO様
無限ループに関しては、
if(row.value[‘分類’].value !== “表紙” && row.value[‘A’].value && row.value[‘B’].value){
の部分をif(row.value[‘分類’].value !== “表紙” && row.value[‘A’].value !== “” && row.value[‘B’].value !== “”){
にしていたからでした。
なので、今は無限ループにはなっていないので、一旦は解決しました。
重複に関しては、やろうとしたいことに関しては仕方ない…といった感じでしょうか?
matsu様
今は無限ループになっていないとのこと,よかったです.
重複処理については,仕様上「changeイベントが正常に動作している」といえるのと,
重複処理は小計の単価の値が変更された1回なので,許容してもよいのかな,と思います.
(2回目は小計の単価が変わらないのでchangeイベントが発火しない)
未検証ですが,kintone.events.onのスコープ外(var events = ~があるところ)で判定用変数を宣言して,
初回の発火時,小計の単価が発火前から変わるなら判定用変数に何かを格納(true/falseなど),
2回目の発火時に判定用変数で初回発火の確認,何もせずに抜ける際に判定用変数を空にする,
という運用であればやりたいことに近い状態になるかと思います.
少しだけ,コードが複雑化する(変数宣言,設定と小計単価の前後比較など)ので,
やりたいことの規模と相談していただければ良いかと思います.
system
(system)
クローズされました:
10
このトピックはベストアンサーに選ばれた返信から 3 日が経過したので自動的にクローズされました。新たに返信することはできません。