Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

9 break time #20

Merged
merged 8 commits into from
Feb 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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