Skip to content

Commit

Permalink
Merge pull request masuidrive#20 from Georepublic/9-break-time
Browse files Browse the repository at this point in the history
9 break time
  • Loading branch information
halsk authored Feb 24, 2020
2 parents cddec81 + 1c8c314 commit 67660ca
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 22 deletions.
13 changes: 12 additions & 1 deletion DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,15 @@ Please say `hi` on your test channel. The bot will create new record on the time

That's All! Pull Requests are very welcome!

You can find additional inormation from [Original Repos](https://github.com/masuidrive/miyamoto)
You can find additional inormation from [Original Repos](https://github.com/masuidrive/miyamoto)


## Update script

When you update the Google Apps Script, you have to create new version for enabling the modification for the API.

1. Run `make dev` and upload the new main.gs.
2. Open your Google Apps script
3. Make a new version from `menu -> manage versions -> save new version`
4. Publish new version from `menu -> Publish -> Deploy as web app` and select the latest version.

70 changes: 61 additions & 9 deletions main.gs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,37 @@ loadDateUtils = function () {
return null;
};

// テキストから休憩時間を抽出
DateUtils.parseMinutes = function(str) {
str = String(str || "").toLowerCase().replace(/[A-Za-z0-9]/g, function(s) {
return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
});
var reg = /(\d*.\d*\s*(分|minutes?|mins|時間|hour|hours))(\d*(分|minutes?|mins))?/;
var matches = str.match(reg);
if(matches) {
var hour = 0;
var min = 0;

// 最初のマッチ
if(matches[1] != null) {
if (['時間','hour','hours'].includes(matches[2])) {
// 1.5 時間
hour = parseFloat(matches[1], 10);
// 2回めのマッチ
if(matches[3] != null) {
min = parseInt(matches[3], 10);
}
} else {
// 60 分
min = parseInt(matches[1], 10);
}
}

return [hour * 60 + min];
}
return null;
};

// テキストから日付を抽出
DateUtils.parseDate = function(str) {
str = String(str || "").toLowerCase().replace(/[A-Za-z0-9]/g, function(s) {
Expand Down Expand Up @@ -327,12 +358,12 @@ loadGSProperties = function (exports) {
var vals = this.sheet.getRange("A1:A"+this.sheet.getLastRow()).getValues();
for(var i = 0; i < this.sheet.getLastRow(); ++i) {
if(vals[i][0] == key) {
this.sheet.getRange("C"+(i+1)).setValue(note);
this.sheet.getRange("D"+(i+1)).setValue(note);
return;
}
}
}
this.sheet.getRange("A"+(this.sheet.getLastRow()+1)+":C"+(this.sheet.getLastRow()+1)).setValues([[key, '', note]]);
this.sheet.getRange("A"+(this.sheet.getLastRow()+1)+":D"+(this.sheet.getLastRow()+1)).setValues([[key, '', note]]);
return;
};

Expand All @@ -358,18 +389,21 @@ loadGSTemplate = function() {
}
else {
var now = DateUtils.now();
this.sheet.getRange("A1:L2").setValues([
this.sheet.getRange("A1:N2").setValues([
[
"出勤", "出勤更新", "退勤", "退勤更新", "休暇", "休暇取消",
"出勤中", "出勤なし", "休暇中", "休暇なし", "出勤確認", "退勤確認"
"出勤", "出勤更新", "退勤", "退勤更新", "休憩", "休暇", "休暇取消",
"出勤中", "出勤なし", "休暇中", "休暇なし", "出勤確認", "退勤確認",
"休憩エラー"
],
[
"<@#1> Good morning (#2)!", "<@#1> I changed starting time to #2",
"<@#1> Great work! (#2)", "<@#1> I changed leaving time to #2",
"<@#1> I changed break time to #2",
"<@#1> I registered a holiday for #2", "<@#1> I canceled holiday #2",
"#1 is working", "All staffs are working",
"#2 is having a holiday at #1", "No one is having a holiday at #1",
"Is today holiday? #1", "Did you finish working today? #1"
"Is today holiday? #1", "Did you finish working today? #1",
"[Error] You have not started working today!"
]
]);
}
Expand Down Expand Up @@ -430,6 +464,7 @@ loadGSTimesheets = function () {
{ name: '日付' },
{ name: '出勤' },
{ name: '退勤' },
{ name: '休憩(分)' },
{ name: 'ノート' },
],
properties: [
Expand Down Expand Up @@ -487,17 +522,17 @@ loadGSTimesheets = function () {
return v === '' ? undefined : v;
});

return({ user: username, date: row[0], signIn: row[1], signOut: row[2], note: row[3] });
return({ user: username, date: row[0], signIn: row[1], signOut: row[2], break: row[3], note: row[4] });
};

GSTimesheets.prototype.set = function(username, date, params) {
var row = this.get(username, date);
_.extend(row, _.pick(params, 'signIn', 'signOut', 'note'));
_.extend(row, _.pick(params, 'signIn', 'signOut', 'break', 'note'));

var sheet = this._getSheet(username);
var rowNo = this._getRowNo(username, date);

var data = [DateUtils.toDate(date), row.signIn, row.signOut, row.note].map(function(v) {
var data = [DateUtils.toDate(date), row.signIn, row.signOut, row.break, row.note].map(function(v) {
return v == null ? '' : v;
});
sheet.getRange("A"+rowNo+":"+String.fromCharCode(65 + this.scheme.columns.length - 1)+rowNo).setValues([data]);
Expand Down Expand Up @@ -733,6 +768,7 @@ loadTimesheets = function (exports) {
// 日付は先に処理しておく
this.date = DateUtils.parseDate(message);
this.time = DateUtils.parseTime(message);
this.minutes = DateUtils.parseMinutes(message)
this.datetime = DateUtils.normalizeDateTime(this.date, this.time);
if(this.datetime !== null) {
this.dateStr = DateUtils.format("Y/m/d", this.datetime);
Expand All @@ -744,6 +780,7 @@ loadTimesheets = function (exports) {
['actionSignOut', /(バ[ー〜ァ]*イ|ば[ー〜ぁ]*い|おやすみ|お[つっ]ー|おつ|さらば|お先|お疲|帰|乙|bye|night|(c|see)\s*(u|you)|left|退勤|ごきげんよ|グ[ッ]?バイ)/],
['actionWhoIsOff', /(だれ|誰|who\s*is).*(休|やす(ま|み|む))/],
['actionWhoIsIn', /(だれ|誰|who\s*is)/],
['actionBreak', /(休憩|break)/],
['actionCancelOff', /(休|やす(ま|み|む)|休暇).*(キャンセル|消|止|やめ|ません)/],
['actionOff', /(休|やす(ま|み|む)|休暇)/],
['actionSignIn', /(モ[ー〜]+ニン|も[ー〜]+にん|おっは|おは|へろ|はろ|ヘロ|ハロ|hi|hello|morning|ohayo|出勤)/],
Expand Down Expand Up @@ -798,6 +835,21 @@ loadTimesheets = function (exports) {
}
};

// 休憩
Timesheets.prototype.actionBreak = function(username, time) {
if (this.minutes) {
var data = this.storage.get(username, this.datetime);
if(!data.signIn || data.signIn === '-') {
// まだ出勤前である
this.responder.template("休憩エラー", username, "" );
} else {
// break 入力
this.storage.set(username, this.datetime, {break: this.minutes});
this.responder.template("休憩", username, this.minutes + "分");
}
}
};

// 休暇申請
Timesheets.prototype.actionOff = function(username, message) {
if(this.date) {
Expand Down
31 changes: 31 additions & 0 deletions scripts/date_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,37 @@ loadDateUtils = function () {
return null;
};

// テキストから休憩時間を抽出
DateUtils.parseMinutes = function(str) {
str = String(str || "").toLowerCase().replace(/[A-Za-z0-9]/g, function(s) {
return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
});
var reg = /(\d*.\d*\s*(分|minutes?|mins|時間|hour|hours))(\d*(分|minutes?|mins))?/;
var matches = str.match(reg);
if(matches) {
var hour = 0;
var min = 0;

// 最初のマッチ
if(matches[1] != null) {
if (['時間','hour','hours'].includes(matches[2])) {
// 1.5 時間
hour = parseFloat(matches[1], 10);
// 2回めのマッチ
if(matches[3] != null) {
min = parseInt(matches[3], 10);
}
} else {
// 60 分
min = parseInt(matches[1], 10);
}
}

return [hour * 60 + min];
}
return null;
};

// テキストから日付を抽出
DateUtils.parseDate = function(str) {
str = String(str || "").toLowerCase().replace(/[A-Za-z0-9]/g, function(s) {
Expand Down
4 changes: 2 additions & 2 deletions scripts/gs_properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ loadGSProperties = function (exports) {
var vals = this.sheet.getRange("A1:A"+this.sheet.getLastRow()).getValues();
for(var i = 0; i < this.sheet.getLastRow(); ++i) {
if(vals[i][0] == key) {
this.sheet.getRange("C"+(i+1)).setValue(note);
this.sheet.getRange("D"+(i+1)).setValue(note);
return;
}
}
}
this.sheet.getRange("A"+(this.sheet.getLastRow()+1)+":C"+(this.sheet.getLastRow()+1)).setValues([[key, '', note]]);
this.sheet.getRange("A"+(this.sheet.getLastRow()+1)+":D"+(this.sheet.getLastRow()+1)).setValues([[key, '', note]]);
return;
};

Expand Down
11 changes: 7 additions & 4 deletions scripts/gs_template.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@ loadGSTemplate = function() {
}
else {
var now = DateUtils.now();
this.sheet.getRange("A1:L2").setValues([
this.sheet.getRange("A1:N2").setValues([
[
"出勤", "出勤更新", "退勤", "退勤更新", "休暇", "休暇取消",
"出勤中", "出勤なし", "休暇中", "休暇なし", "出勤確認", "退勤確認"
"出勤", "出勤更新", "退勤", "退勤更新", "休憩", "休暇", "休暇取消",
"出勤中", "出勤なし", "休暇中", "休暇なし", "出勤確認", "退勤確認",
"休憩エラー"
],
[
"<@#1> Good morning (#2)!", "<@#1> I changed starting time to #2",
"<@#1> Great work! (#2)", "<@#1> I changed leaving time to #2",
"<@#1> I changed break time to #2",
"<@#1> I registered a holiday for #2", "<@#1> I canceled holiday #2",
"#1 is working", "All staffs are working",
"#2 is having a holiday at #1", "No one is having a holiday at #1",
"Is today holiday? #1", "Did you finish working today? #1"
"Is today holiday? #1", "Did you finish working today? #1",
"[Error] You have not started working today!"
]
]);
}
Expand Down
7 changes: 4 additions & 3 deletions scripts/gs_timesheets.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ loadGSTimesheets = function () {
{ name: '日付' },
{ name: '出勤' },
{ name: '退勤' },
{ name: '休憩(分)' },
{ name: 'ノート' },
],
properties: [
Expand Down Expand Up @@ -69,17 +70,17 @@ loadGSTimesheets = function () {
return v === '' ? undefined : v;
});

return({ user: username, date: row[0], signIn: row[1], signOut: row[2], note: row[3] });
return({ user: username, date: row[0], signIn: row[1], signOut: row[2], break: row[3], note: row[4] });
};

GSTimesheets.prototype.set = function(username, date, params) {
var row = this.get(username, date);
_.extend(row, _.pick(params, 'signIn', 'signOut', 'note'));
_.extend(row, _.pick(params, 'signIn', 'signOut', 'break', 'note'));

var sheet = this._getSheet(username);
var rowNo = this._getRowNo(username, date);

var data = [DateUtils.toDate(date), row.signIn, row.signOut, row.note].map(function(v) {
var data = [DateUtils.toDate(date), row.signIn, row.signOut, row.break, row.note].map(function(v) {
return v == null ? '' : v;
});
sheet.getRange("A"+rowNo+":"+String.fromCharCode(65 + this.scheme.columns.length - 1)+rowNo).setValues([data]);
Expand Down
17 changes: 17 additions & 0 deletions scripts/timesheets.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ loadTimesheets = function (exports) {
// 日付は先に処理しておく
this.date = DateUtils.parseDate(message);
this.time = DateUtils.parseTime(message);
this.minutes = DateUtils.parseMinutes(message)
this.datetime = DateUtils.normalizeDateTime(this.date, this.time);
if(this.datetime !== null) {
this.dateStr = DateUtils.format("Y/m/d", this.datetime);
Expand All @@ -29,6 +30,7 @@ loadTimesheets = function (exports) {
['actionSignOut', /(バ[ー〜ァ]*イ|ば[ー〜ぁ]*い|おやすみ|お[つっ]ー|おつ|さらば|お先|お疲|帰|乙|bye|night|(c|see)\s*(u|you)|left|退勤|ごきげんよ|グ[ッ]?バイ)/],
['actionWhoIsOff', /(だれ|誰|who\s*is).*(休|やす(ま|み|む))/],
['actionWhoIsIn', /(だれ|誰|who\s*is)/],
['actionBreak', /(休憩|break)/],
['actionCancelOff', /(休|やす(ま|み|む)|休暇).*(キャンセル|消|止|やめ|ません)/],
['actionOff', /(休|やす(ま|み|む)|休暇)/],
['actionSignIn', /(モ[ー〜]+ニン|も[ー〜]+にん|おっは|おは|へろ|はろ|ヘロ|ハロ|hi|hello|morning|ohayo|出勤)/],
Expand Down Expand Up @@ -83,6 +85,21 @@ loadTimesheets = function (exports) {
}
};

// 休憩
Timesheets.prototype.actionBreak = function(username, time) {
if (this.minutes) {
var data = this.storage.get(username, this.datetime);
if(!data.signIn || data.signIn === '-') {
// まだ出勤前である
this.responder.template("休憩エラー", username, "" );
} else {
// break 入力
this.storage.set(username, this.datetime, {break: this.minutes});
this.responder.template("休憩", username, this.minutes + "分");
}
}
};

// 休暇申請
Timesheets.prototype.actionOff = function(username, message) {
if(this.date) {
Expand Down
8 changes: 6 additions & 2 deletions testrunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ var runner = require("./node_modules/qunit");
runner.setup({
log: {
assertions: true,
summary: true
summary: true,
coverage: true,
errors: true
}
});

Expand Down Expand Up @@ -34,4 +36,6 @@ runner.run([
"./scripts/date_utils.js",
]
}
]);
], function(err, report) {
console.dir(report);
});
14 changes: 14 additions & 0 deletions tests/date_utils_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ QUnit.test( "DateUtils.parseTime", function(assert) {
assert.ok(_.isEqual(null, DateUtils.parseTime("お昼")), "お昼");
});

QUnit.test( "DateUtils.parseMinutes", function(assert) {
assert.ok(_.isEqual([90], DateUtils.parseMinutes("90分")), "90分");
assert.ok(_.isEqual([90], DateUtils.parseMinutes("90 minutes")), "90 minutes");
assert.ok(_.isEqual([90], DateUtils.parseMinutes("90 mins")), "90 mins");
assert.ok(_.isEqual([1], DateUtils.parseMinutes("1 minute")), "1 minute");
assert.ok(_.isEqual([90], DateUtils.parseMinutes("90 mins")), "90 mins");
assert.ok(_.isEqual([90], DateUtils.parseMinutes("1.5時間")), "1.5時間");
assert.ok(_.isEqual([60], DateUtils.parseMinutes("1時間")), "1時間");
assert.ok(_.isEqual([60], DateUtils.parseMinutes("1 hour")), "1 hour");
assert.ok(_.isEqual([60], DateUtils.parseMinutes("60分")), "60分");
assert.ok(_.isEqual([120], DateUtils.parseMinutes("2 hours")), "2 hours");
assert.ok(_.isEqual([135], DateUtils.parseMinutes("2時間15分")), "2時間15分");
});

QUnit.test( "DateUtils.parseDate", function(assert) {
DateUtils.now(new Date(2016, 1-1, 1, 0, 0, 0));
assert.ok(_.isEqual([2015,12,1], DateUtils.parseDate("12/1")), "12/1");
Expand Down
16 changes: 15 additions & 1 deletion tests/timesheets_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ QUnit.test( "Timesheets", function(assert) {
set: function(username, date, params) {
var row = this.get(username, date);
row.user = username;
_.extend(row, _.pick(params, 'signIn', 'signOut', 'note'));
_.extend(row, _.pick(params, 'signIn', 'signOut','break', 'note'));
this.data[username][String(DateUtils.toDate(date))] = row;
return row;
},
Expand Down Expand Up @@ -143,6 +143,20 @@ QUnit.test( "Timesheets", function(assert) {
msgTest('test1', 'お疲れさま 14:56', [['退勤更新', 'test1', "2014/01/02 14:56"]]);
});

// 休憩時間(出勤前)
var test1 = {};
test1[nowDateStr()] = { user: 'test1', signIn: new Date(2014,0,2,0,0,0), signOut: new Date(2014,0,2,12,0,0) };
storageTest({'test1': test1}, function(msgTest) {
msgTest('test1', '休憩 30分', [['休憩', 'test1', "30分"]]);
});

// 休憩時間(出勤後)
test1 = {};
test1[nowDateStr()] = { user: 'test1', signIn: new Date(2014,0,2,0,0,0), signOut: new Date(2014,0,2,12,0,0) };
storageTest({}, function(msgTest) {
msgTest('test1', '休憩 30分', [['休憩エラー', 'test1']]);
});

// 休暇申請
storageTest({}, function(msgTest) {
msgTest('test1', 'お休み', []);
Expand Down

0 comments on commit 67660ca

Please sign in to comment.