テーブルの計算について

お世話になっております。

有休計算について② を参照にしたいですが、初心者のため、どう応用すればよろしいかわからなくて、彷徨っております。

以下のコードでは「県内実務時間」、「県外実務時間」を時間単位での合計が反映されなくて、また「時間外」は「終了」時間が 19時以降 であれば、合計したいですが、全然動けなくて、ご教授いただけたら、幸いです。ぜひよろしくお願い致します。

 

(function() {
“use strict”;
kintone.events.on([“app.record.create.show”,“app.record.edit.show”,“app.record.create.change.Table”, “app.record.edit.change.Table”], function(event) {
event.record.県内実務時間.disabled = true;
event.record.県外実務時間.disabled = true;
var table = event.record.Table.value;
for (var i = 0, l = table.length; i < l; i++) {
event.record.Table.value[i].value.勤務時間.disabled = true;
}
return event;
});
kintone.events.on([
“app.record.create.change.開始”, “app.record.edit.change.開始”,
“app.record.create.change.終了”, “app.record.edit.change.終了”,
“app.record.create.change.休憩”, “app.record.edit.change.休憩”,
], function(event) {
event.changes.row.value.勤務時間.value = event.changes.row.value.開始.value;
var start_time;
var end_time;
var time;
var hour;
var minute;
if(typeof event.changes.row.value.開始.value !== “undefined” && typeof event.changes.row.value.終了.value !== “undefined” && typeof event.changes.row.value.休憩.value !== “undefined”){
start_time = event.changes.row.value.開始.value.split(‘:’);
end_time = event.changes.row.value.終了.value.split(‘:’);
time = (Number(end_time[0]) * 60 + Number(end_time[1])) - (Number(start_time[0]) * 60 + Number(start_time[1])) - Number(event.changes.row.value.休憩.value);
hour = time / 60;
event.changes.row.value.勤務時間.value = hour + “時間” ;
}else{
event.changes.row.value.勤務時間.value = undefined;
}
return event;
});

function calcDays(event){
var record = event.record;
var types = [
{radioLabel:‘県内’, daysFieldCode:‘県内実務時間’},
{radioLabel:‘県外’, daysFieldCode:‘県外実務時間’},
];
types.forEach(function(type){
var time = [];
var sum = 0;

for (var i = 0; i < record.Table.value.length; i++) {
if (record.Table.value[i].value.形態.value === type.radioLabel && typeof record.Table.value[i].value.勤務時間.value !== “undefined”) {
time = record.Table.value[i].value.勤務時間.value;
}
}
record[type.daysFieldCode].value = time + “時間”;
});
return event;
}
})();

 

篠原さん

時間計算は、moment.js を使うと便利です。サンプルコードです。

計算結果に影響がある区分の変更なども考慮しましょう。

時間外に、0時以降も考慮する必要がある場合は、変更が必要です。

※あと、テーブル内に時間外の項目を持った方が分かりやすいと思います。

 

(function() {
"use strict";
kintone.events.on(["app.record.create.show", "app.record.edit.show", "app.record.create.change.Table", "app.record.edit.change.Table"], function(event) {
event.record.県内実務時間.disabled = true;
event.record.県外実務時間.disabled = true;
event.record.時間外.disabled = true;
var table = event.record.Table.value;
table.forEach(function(row) {
row.value.勤務時間.disabled = true;
});
return event;
});
kintone.events.on([
"app.record.create.show", "app.record.edit.show", "app.record.create.change.Table", "app.record.edit.change.Table",
"app.record.create.submit", "app.record.edit.submit",
"app.record.create.change.区分", "app.record.edit.change.区分",
"app.record.create.change.開始", "app.record.edit.change.開始",
"app.record.create.change.終了", "app.record.edit.change.終了",
"app.record.create.change.休憩", "app.record.edit.change.休憩",
], function(event) {
var record = event.record;
var mwork = { '県内実務時間': moment.duration(0), '県外実務時間': moment.duration(0), '時間外': moment.duration(0) };
var table = record.Table.value;
table.forEach(function(row) {
if (row.value.開始.value && row.value.終了.value && row.value.休憩.value) {
var whours = moment.duration(row.value.終了.value).subtract(moment.duration(row.value.開始.value)).subtract(Number(row.value.休憩.value), 'minutes');
if (whours.as('hours') > 0) {
row.value.勤務時間.value = whours.get('hours') + '時間 ' + whours.get('minutes') + '分';
var kubun = row.value.区分.value + '実務時間';
mwork[kubun] = mwork[kubun].add(whours);
if (row.value.終了.value > '19:00') {
var overtime = moment.duration(row.value.終了.value).subtract('19:00');
mwork['時間外'] = mwork['時間外'].add(overtime);
}
}
else {
row.value.終了.error = '開始 > 終了';
}
} else {
row.value.勤務時間.value = '';
}
});
Object.keys(mwork).forEach(function(key) {
record[key].value = parseInt(mwork[key].as('hours')) + '時間 ' + mwork[key].get('minutes') + '分';
});
return event;
});

})();

rex0220 様

ご指導ありがとうございます。

作りたかったようにできそうで本当にありがとうございます。

ただ、項目別に〇時間〇分⇒〇時間のみに表示させるのは可能でしょうか?

再びアドバイス頂けると幸いです。よろしくお願い致します。

時間の場合は、循環小数になる場合があります。

御社の規則に合わせて、切り捨て等行ってください。

record[key].value = mwork[key].as(‘hours’) + '時間 ';

ご参考に、計算式プラグインで勤務時間を集計できるようにしてみました。

Excel の計算式のような設定で、時間集計が出来ます。

  • テーブル内の時刻項目を計算して、勤務時間を集計します。

  • テーブル内の時刻項目から勤務時間を計算します。

 

機会がございましたら、お試しください。

 

 

 

 

rex0220 様

お世話になっております。色々ととても素敵なアドバイスいただき、本当にありがとうございます。moment.js まだ全然詳しくないですが、以下のコードでは、計算式も入ってないので、どうして勤務時間が計算されるのか不思議で、初心者で大変申し訳ございませんが、コードの説明も教えて頂いたら幸いです。

table.forEach(function(row) {
if (row.value.開始.value && row.value.終了.value && row.value.休憩.value) {
var whours = moment.duration(row.value.終了.value).subtract(moment.duration(row.value.開始.value)).subtract(Number(row.value.休憩.value), 'minutes');
if (whours.as('hours') > 0) {
row.value.勤務時間.value = whours.get('hours') + '時間 ' + whours.get('minutes') + '分';

[計算式プラグインで勤務時間を集計](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73#%E6%99%82%E9%96%93%E9%9B%86%E8%A8%88%E3%81%AE%E8%A8%AD%E5%AE%9A)とてもすばらしいですね。ぜひ試してみたいと思います。
本当にありがとうございます。

moment.js は、日付関連のいろいろな機能をもっており、その中に期間に関する機能を持っている moment.duration があります。

>計算式も入ってないので、どうして勤務時間が計算されるのか

慣れないと分かりにくいですが、下記には計算式があります。

var whours = moment.duration(row.value.終了.value).subtract(moment.duration(row.value.開始.value)).subtract(Number(row.value.休憩.value), ‘minutes’);

意味的には、時刻や数字をミリセカンド単位に変換して、下記のような計算をしています。
var whours = 終了 - 開始 - 休憩

moment.duration(row.value.終了.value)

これは、 “20:00” などの時刻を表している文字列(row.value.終了.value)から、期間を扱う duration を初期化します。
内部的には、ミリセカンドの時間単位で持っています。

subtract(moment.duration(row.value.開始.value))

subtract は、引き算です。

“09:00” などの時刻を表している文字列(row.value.開始.value)から、期間を扱う duration 形式に変換後、
左辺に記述されている、moment.duration(row.value.終了.value) から、値を引きます。

subtract(Number(row.value.休憩.value), ‘minutes’);

これも同様ですが、パラメータの形式が 分単位の数字ということを明示しています。

row.value.勤務時間.value = whours.get(‘hours’) + '時間 ’ + whours.get(‘minutes’) + ‘分’;

whours.get(‘hours’) は、 duration 形式で持っている値から、「時間」の部分を取り出します。

whours.get(‘minutes’)は、同じく「分」の部分を取り出します。

record[key].value = mwork[key].as(‘hours’) + '時間 ';

mwork[key].as(‘hours’) は、duration 形式で持っている値を、「時間」に換算した値を取り出します。

下記のような違いです。

moment.duration(‘12:30’).as(‘hours’) -> 12.5
moment.duration(‘12:30’).get(‘hours’) -> 12

moment.duration に関しては、あまり日本語の解説が見当たりませんので、本家を見るのが一番です。
https://momentjs.com/docs/#/durations/

英語ですが、内容はサンプルが多いので単語だけ見てもわかりやすいと思います。

rex0220 様

大変お世話になっております。ご丁寧に教えていただき、誠にありがとうございます。とても勉強になりました。

お忙しいところ、大変恐縮で本当に申し訳ございませんが、以下のように変更したいですが、コード形式が全然違うので、混乱しておりまして、

どこから入手すればいいかでも構わないですが、なにかアドバイスいただけますでしょうか?

 

有休計算について②を真似して、有休状況を加えたいと思いまして

規定労働時間⇒有休を選択した場合、日数と時間数で合計:有給数

実務日数:有給以外を選択した場合の合計日数

有休計算について②rex0220 さんのコードの組み方がちょっと違うので、うまく組み合わせができなくて・・・

もし可能であれば、ぜひアドバイスよろしくお願い致します。

 

有給数と実務日数の処理は、初期設定と足し算なので、下記のように処理を追加してはどうでしょうか?

ただし、開始・終了・休憩・有給の整合性チェックを入れないと、運用上トラブルが多くなると思います。

 

(function() {
"use strict";
kintone.events.on(["app.record.create.show", "app.record.edit.show", "app.record.create.change.Table", "app.record.edit.change.Table"], function(event) {
event.record.県内実務時間.disabled = true;
event.record.県外実務時間.disabled = true;
event.record.時間外.disabled = true;
event.record.有給数.disabled = true;
event.record.実務日数.disabled = true;
var table = event.record.Table.value;
table.forEach(function(row) {
row.value.勤務時間.disabled = true;
});
return event;
});
kintone.events.on([
"app.record.create.show", "app.record.edit.show", "app.record.create.change.Table", "app.record.edit.change.Table",
"app.record.create.submit", "app.record.edit.submit",
"app.record.create.change.区分", "app.record.edit.change.区分",
"app.record.create.change.開始", "app.record.edit.change.開始",
"app.record.create.change.終了", "app.record.edit.change.終了",
"app.record.create.change.休憩", "app.record.edit.change.休憩",
], function(event) {
var record = event.record;
var mwork = { '県内実務時間': moment.duration(0), '県外実務時間': moment.duration(0), '時間外': moment.duration(0) };
var mcount = { '有給数': moment.duration(0), '実務日数': 0 };
var table = record.Table.value;
table.forEach(function(row) {
if (row.value.開始.value && row.value.終了.value && row.value.休憩.value) {
var whours = moment.duration(row.value.終了.value).subtract(moment.duration(row.value.開始.value)).subtract(Number(row.value.休憩.value), 'minutes');
if (whours.as('hours') > 0) {
row.value.勤務時間.value = whours.get('hours') + '時間 ' + whours.get('minutes') + '分';
if (row.value.区分.value === '有給') {
mcount['有給数'] = mcount['有給数'].add(whours);
}
else {
mcount['実務日数']++;
var kubun = row.value.区分.value + '実務時間';
mwork[kubun] = mwork[kubun].add(whours);
if (row.value.終了.value > '19:00') {
var overtime = moment.duration(row.value.終了.value).subtract('19:00');
mwork['時間外'] = mwork['時間外'].add(overtime);
}
}
}
else {
row.value.終了.error = '開始 > 終了';
}
} else {
row.value.勤務時間.value = '';
}
});
Object.keys(mwork).forEach(function(key) {
record[key].value = mwork[key].as('hours') + '時間 ';
});
if (record.規定労働時間.value && Number(record.規定労働時間.value) > 0) {
var pwh = Number(record.規定労働時間.value);
record['有給数'].value = parseInt(mcount['有給数'].as('hours') / pwh) + ' 日 ' + mcount['有給数'].as('hours') % pwh + '時間';
}
else {
record['有給数'].value = '';
}
record['実務日数'].value = mcount['実務日数'] + ' 日';
return event;
});

})();

rex0220 様

お世話になっております。

何度もコードまで書いていただき、本当にありがとうございます。とても悩んでおりましたので、本当にとても助かりました。

感動と感謝でいっぱいです。本当にどうもありがとうございました。

rex0220 様

いつもお世話になっております。

大変申し訳ございませんが、もうひとつ教えていただけますでしょうか?

今同じ日に県内と県外を選んだ場合、実務日数がカウントされますが、同じ日であれば、県内・県外の場合は1カウントされる設定は可能でしょうか?

お手数をおかけまして、大変申し訳ございませんが、アドバイスいただけるようよろしくお願い致します。

なるほど、そういうケースもあるんですね。

日付でカウントしましょう。

 

(function() {
"use strict";
kintone.events.on(["app.record.create.show", "app.record.edit.show", "app.record.create.change.Table", "app.record.edit.change.Table"], function(event) {
event.record.県内実務時間.disabled = true;
event.record.県外実務時間.disabled = true;
event.record.時間外.disabled = true;
event.record.有給数.disabled = true;
event.record.実務日数.disabled = true;
var table = event.record.Table.value;
table.forEach(function(row) {
row.value.勤務時間.disabled = true;
});
return event;
});
kintone.events.on([
"app.record.create.show", "app.record.edit.show", "app.record.create.change.Table", "app.record.edit.change.Table",
"app.record.create.submit", "app.record.edit.submit",
"app.record.create.change.日付", "app.record.edit.change.日付",
"app.record.create.change.区分", "app.record.edit.change.区分",
"app.record.create.change.開始", "app.record.edit.change.開始",
"app.record.create.change.終了", "app.record.edit.change.終了",
"app.record.create.change.休憩", "app.record.edit.change.休憩",
], function(event) {
var record = event.record;
var mwork = { '県内実務時間': moment.duration(0), '県外実務時間': moment.duration(0), '時間外': moment.duration(0) };
var mcount = { '有給数': moment.duration(0), '実務日数': {} };
var table = record.Table.value;
table.forEach(function(row) {
if (row.value.開始.value && row.value.終了.value && row.value.休憩.value) {
var whours = moment.duration(row.value.終了.value).subtract(moment.duration(row.value.開始.value)).subtract(Number(row.value.休憩.value), 'minutes');
if (whours.as('hours') > 0) {
row.value.勤務時間.value = whours.get('hours') + '時間 ' + whours.get('minutes') + '分';
if (row.value.区分.value === '有給') {
mcount['有給数'] = mcount['有給数'].add(whours);
}
else {
mcount['実務日数'][row.value.日付.value] = 1;
var kubun = row.value.区分.value + '実務時間';
mwork[kubun] = mwork[kubun].add(whours);
if (row.value.終了.value > '19:00') {
var overtime = moment.duration(row.value.終了.value).subtract('19:00');
mwork['時間外'] = mwork['時間外'].add(overtime);
}
}
}
else {
row.value.終了.error = '開始 > 終了';
}
} else {
row.value.勤務時間.value = '';
}
});
Object.keys(mwork).forEach(function(key) {
record[key].value = mwork[key].as('hours') + '時間 ';
});
if (record.規定労働時間.value && Number(record.規定労働時間.value) > 0) {
var pwh = Number(record.規定労働時間.value);
record['有給数'].value = parseInt(mcount['有給数'].as('hours') / pwh) + ' 日 ' + mcount['有給数'].as('hours') % pwh + '時間';
}
else {
record['有給数'].value = '';
}
record['実務日数'].value = Object.keys(mcount['実務日数']).length + ' 日';
return event;
});

})();

rex0220 様

いつもお世話になっております。素晴らしいです。感動(涙)

いつも助けて頂き、本当にありがとうございます。とても助かりました。これからもどうぞよろしくお願い致します。