diff --git a/Gemfile b/Gemfile
index f62ef445..4b181f9e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,7 +2,7 @@
source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
-gem 'rails', '>= 5.0.0.rc1', '< 5.1'
+gem 'rails', '>= 5.0.7'
# Use postgresql as the database for Active Record
gem 'pg', '~> 0.18'
# Use Puma as the app server
@@ -17,8 +17,7 @@ gem 'coffee-rails', '~> 4.1.0'
# gem 'therubyracer', platforms: :ruby
# Use jquery as the JavaScript library
gem 'jquery-rails'
-# Use bootstrap3 datetimepicker library
-gem 'bootstrap3-datetimepicker-rails'
+gem 'flatpickr'
gem 'momentjs-rails'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5.x'
@@ -52,6 +51,10 @@ gem 'crono'
gem 'sinatra', require: nil
gem 'daemons'
gem 'flowdock'
+gem 'act-fluent-logger-rails'
+gem 'lograge'
+gem 'logstash-event'
+gem 'capybara'
group :development, :test do
gem 'awesome_print'
diff --git a/Gemfile.lock b/Gemfile.lock
index da8807f9..7040e18b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -27,45 +27,49 @@ GEM
specs:
aasm (4.12.0)
concurrent-ruby (~> 1.0)
- actioncable (5.0.3)
- actionpack (= 5.0.3)
+ act-fluent-logger-rails (0.4.0)
+ activesupport (>= 4, < 5.2)
+ fluent-logger
+ railties (>= 4, < 5.2)
+ actioncable (5.0.7)
+ actionpack (= 5.0.7)
nio4r (>= 1.2, < 3.0)
websocket-driver (~> 0.6.1)
- actionmailer (5.0.3)
- actionpack (= 5.0.3)
- actionview (= 5.0.3)
- activejob (= 5.0.3)
+ actionmailer (5.0.7)
+ actionpack (= 5.0.7)
+ actionview (= 5.0.7)
+ activejob (= 5.0.7)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
- actionpack (5.0.3)
- actionview (= 5.0.3)
- activesupport (= 5.0.3)
+ actionpack (5.0.7)
+ actionview (= 5.0.7)
+ activesupport (= 5.0.7)
rack (~> 2.0)
rack-test (~> 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
- actionview (5.0.3)
- activesupport (= 5.0.3)
+ actionview (5.0.7)
+ activesupport (= 5.0.7)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_hash (1.5.1)
activesupport (>= 2.2.2)
- activejob (5.0.3)
- activesupport (= 5.0.3)
+ activejob (5.0.7)
+ activesupport (= 5.0.7)
globalid (>= 0.3.6)
- activemodel (5.0.3)
- activesupport (= 5.0.3)
- activerecord (5.0.3)
- activemodel (= 5.0.3)
- activesupport (= 5.0.3)
+ activemodel (5.0.7)
+ activesupport (= 5.0.7)
+ activerecord (5.0.7)
+ activemodel (= 5.0.7)
+ activesupport (= 5.0.7)
arel (~> 7.0)
activerecord-import (0.18.3)
activerecord (>= 3.2)
- activesupport (5.0.3)
+ activesupport (5.0.7)
concurrent-ruby (~> 1.0, >= 1.0.2)
- i18n (~> 0.7)
+ i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
addressable (2.5.0)
@@ -73,7 +77,7 @@ GEM
airbrussh (1.2.0)
sshkit (>= 1.6.1, != 1.7.0)
arel (7.1.4)
- ast (2.3.0)
+ ast (2.4.0)
autoprefixer-rails (7.1.0)
execjs
awesome_print (1.7.0)
@@ -85,8 +89,6 @@ GEM
bootstrap-sass (3.3.7)
autoprefixer-rails (>= 5.2.1)
sass (>= 3.3.4)
- bootstrap3-datetimepicker-rails (4.17.47)
- momentjs-rails (>= 2.8.1)
builder (3.2.3)
byebug (9.0.6)
cancancan (1.16.0)
@@ -106,6 +108,13 @@ GEM
capistrano-bundler (~> 1.1)
capistrano-upload-config (0.7.0)
capistrano (>= 3.0)
+ capybara (2.16.1)
+ addressable
+ mini_mime (>= 0.1.3)
+ nokogiri (>= 1.3.3)
+ rack (>= 1.0.0)
+ rack-test (>= 0.5.4)
+ xpath (~> 2.0)
chronic (0.10.2)
clavius (1.0.2)
cocoon (1.2.10)
@@ -120,6 +129,7 @@ GEM
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.0.5)
+ crass (1.0.4)
crono (1.1.2)
activerecord (>= 4.0)
activesupport (>= 4.0)
@@ -146,10 +156,13 @@ GEM
faker (1.7.3)
i18n (~> 0.5)
ffi (1.9.18)
+ flatpickr (2.6.3.0)
flowdock (0.7.1)
httparty (~> 0.7)
multi_json
- globalid (0.4.0)
+ fluent-logger (0.7.1)
+ msgpack (>= 1.0.0, < 2)
+ globalid (0.4.1)
activesupport (>= 4.2.0)
haml (5.0.1)
temple (>= 0.8.0)
@@ -160,7 +173,8 @@ GEM
unicode-display_width (~> 0.1.1)
httparty (0.15.5)
multi_xml (>= 0.5.2)
- i18n (0.8.1)
+ i18n (0.9.5)
+ concurrent-ruby (~> 1.0)
i18n-debug (1.1.0)
i18n (< 1)
jbuilder (2.6.4)
@@ -190,36 +204,41 @@ GEM
listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
- loofah (2.0.3)
+ lograge (0.5.1)
+ actionpack (>= 4, < 5.2)
+ activesupport (>= 4, < 5.2)
+ railties (>= 4, < 5.2)
+ logstash-event (1.2.02)
+ loofah (2.2.2)
+ crass (~> 1.0.2)
nokogiri (>= 1.5.9)
- mail (2.6.5)
- mime-types (>= 1.16, < 4)
+ mail (2.7.0)
+ mini_mime (>= 0.1.1)
method_source (0.8.2)
- mime-types (3.1)
- mime-types-data (~> 3.2015)
- mime-types-data (3.2016.0521)
- mini_portile2 (2.1.0)
- minitest (5.10.2)
+ mini_mime (1.0.0)
+ mini_portile2 (2.3.0)
+ minitest (5.11.3)
momentjs-rails (2.17.1)
railties (>= 3.1)
+ msgpack (1.1.0)
multi_json (1.12.1)
multi_xml (0.6.0)
mustermann (1.0.0)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (4.1.0)
- nio4r (2.0.0)
- nokogiri (1.7.2)
- mini_portile2 (~> 2.1.0)
+ nio4r (2.3.1)
+ nokogiri (1.8.3)
+ mini_portile2 (~> 2.3.0)
orm_adapter (0.5.0)
paranoia (2.3.1)
activerecord (>= 4.0, < 5.2)
- parser (2.4.0.0)
- ast (~> 2.2)
+ parser (2.5.1.0)
+ ast (~> 2.4.0)
pg (0.20.0)
polyamorous (1.3.1)
activerecord (>= 3.0)
- powerpack (0.1.1)
+ powerpack (0.1.2)
pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
@@ -229,24 +248,24 @@ GEM
pry (~> 0.10)
public_suffix (2.0.5)
puma (3.8.2)
- rack (2.0.3)
+ rack (2.0.5)
rack-mini-profiler (0.10.2)
rack (>= 1.2.0)
rack-protection (2.0.0)
rack
rack-test (0.6.3)
rack (>= 1.0)
- rails (5.0.3)
- actioncable (= 5.0.3)
- actionmailer (= 5.0.3)
- actionpack (= 5.0.3)
- actionview (= 5.0.3)
- activejob (= 5.0.3)
- activemodel (= 5.0.3)
- activerecord (= 5.0.3)
- activesupport (= 5.0.3)
- bundler (>= 1.3.0, < 2.0)
- railties (= 5.0.3)
+ rails (5.0.7)
+ actioncable (= 5.0.7)
+ actionmailer (= 5.0.7)
+ actionpack (= 5.0.7)
+ actionview (= 5.0.7)
+ activejob (= 5.0.7)
+ activemodel (= 5.0.7)
+ activerecord (= 5.0.7)
+ activesupport (= 5.0.7)
+ bundler (>= 1.3.0)
+ railties (= 5.0.7)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.1)
actionpack (~> 5.x)
@@ -255,17 +274,17 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
- rails-html-sanitizer (1.0.3)
- loofah (~> 2.0)
- railties (5.0.3)
- actionpack (= 5.0.3)
- activesupport (= 5.0.3)
+ rails-html-sanitizer (1.0.4)
+ loofah (~> 2.2, >= 2.2.2)
+ railties (5.0.7)
+ actionpack (= 5.0.7)
+ activesupport (= 5.0.7)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.2.2)
rake
- rake (12.0.0)
+ rake (12.3.1)
rb-fsevent (0.9.8)
rb-inotify (0.9.8)
ffi (>= 0.5.0)
@@ -294,7 +313,7 @@ GEM
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
- ruby-progressbar (1.8.1)
+ ruby-progressbar (1.9.0)
sass (3.4.23)
sass-rails (5.0.6)
railties (>= 4.0.0, < 6)
@@ -329,10 +348,10 @@ GEM
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
- sprockets (3.7.1)
+ sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
- sprockets-rails (3.2.0)
+ sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
@@ -340,14 +359,14 @@ GEM
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
temple (0.8.0)
- thor (0.19.4)
+ thor (0.20.0)
thread_safe (0.3.6)
tilt (2.0.7)
timecop (0.8.1)
turbolinks (5.0.1)
turbolinks-source (~> 5)
turbolinks-source (5.0.3)
- tzinfo (1.2.3)
+ tzinfo (1.2.5)
thread_safe (~> 0.1)
uglifier (3.2.0)
execjs (>= 0.3.0, < 3)
@@ -361,27 +380,30 @@ GEM
railties (>= 5.0)
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
- websocket-extensions (0.1.2)
+ websocket-extensions (0.1.3)
whenever (0.9.7)
chronic (>= 0.6.3)
+ xpath (2.1.0)
+ nokogiri (~> 1.3)
PLATFORMS
ruby
DEPENDENCIES
aasm
+ act-fluent-logger-rails
active_hash
activerecord-import
awesome_print
biz
bootstrap-sass
- bootstrap3-datetimepicker-rails
byebug
cancancan
capistrano (~> 3.8.1)
capistrano-crono
capistrano-rails (~> 1.1)
capistrano-upload-config
+ capybara
cocoon
codeclimate-test-reporter (~> 1.0.0)
coffee-rails (~> 4.1.0)
@@ -392,6 +414,7 @@ DEPENDENCIES
devise
factory_girl_rails
faker
+ flatpickr
flowdock
haml
hirb-unicode
@@ -401,6 +424,8 @@ DEPENDENCIES
kaminari
letter_opener
listen (~> 3.0.5)
+ lograge
+ logstash-event
momentjs-rails
paranoia (~> 2.2)
pg (~> 0.18)
@@ -408,7 +433,7 @@ DEPENDENCIES
pry-byebug
puma (~> 3.0)
rack-mini-profiler (~> 0.10.1)
- rails (>= 5.0.0.rc1, < 5.1)
+ rails (>= 5.0.7)
rails-controller-testing
rails-observers!
ransack!
@@ -432,4 +457,4 @@ DEPENDENCIES
whenever
BUNDLED WITH
- 1.15.1
+ 1.16.2
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index f8d38c50..63bbb180 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -4,6 +4,8 @@
//= require bootstrap-sprockets
//= require cocoon
//= require moment
-//= require bootstrap-datetimepicker
+//= require flatpickr
+//= require datepicker
+//= require datetimepicker
//= require base
-//= require bootstrap3-datetimepicker
+//= require page_alert
diff --git a/app/assets/javascripts/bootstrap3-datetimepicker.js b/app/assets/javascripts/bootstrap3-datetimepicker.js
deleted file mode 100644
index f1f43463..00000000
--- a/app/assets/javascripts/bootstrap3-datetimepicker.js
+++ /dev/null
@@ -1,25 +0,0 @@
-document.addEventListener('turbolinks:load', function() {
- var datePicker = {
- $datePickers: $("*[data-input='datepicker']"),
-
- initDatePickers: function(elem) {
- $(elem).datetimepicker({
- format: $(elem).data('format'),
- sideBySide: true,
- stepping: 30,
- useCurrent: false,
- // TODO: disabledTimeIntervals should be changed according to business hours settings
- disabledTimeIntervals: [[moment({ h: 0 }), moment({ h: 9, m: 29 })], [moment({ h: 18, m: 31 }), moment({ h: 24 })]]
- });
- },
-
- init: function() {
- var $this = this;
- $this.$datePickers.each(function() {
- $this.initDatePickers(this);
- });
- }
- };
-
- datePicker.init();
-});
diff --git a/app/assets/javascripts/datepicker.js b/app/assets/javascripts/datepicker.js
new file mode 100644
index 00000000..1c2ce6a3
--- /dev/null
+++ b/app/assets/javascripts/datepicker.js
@@ -0,0 +1,21 @@
+document.addEventListener('turbolinks:load', function() {
+ var datePicker = {
+ $datePickers: $("*[data-input='datepicker']"),
+
+ initDatePickers: function(elem) {
+ $(elem).flatpickr({
+ enableTime: false,
+ dateFormat: $(elem).data('format')
+ });
+ },
+
+ init: function() {
+ var $this = this;
+ $this.$datePickers.each(function() {
+ $this.initDatePickers(this);
+ });
+ }
+ };
+
+ datePicker.init();
+});
diff --git a/app/assets/javascripts/datetimepicker.js b/app/assets/javascripts/datetimepicker.js
new file mode 100644
index 00000000..9607daf4
--- /dev/null
+++ b/app/assets/javascripts/datetimepicker.js
@@ -0,0 +1,25 @@
+document.addEventListener('turbolinks:load', function() {
+ var dateTimePicker = {
+ $dateTimePickers: $("*[data-input='datetimepicker']"),
+
+ initDateTimePickers: function(elem) {
+ $(elem).flatpickr({
+ defaultHour: 9,
+ defaultMinute: 30,
+ enableTime: true,
+ dateFormat: $(elem).data('format'),
+ time_24hr: true,
+ minuteIncrement: 30
+ });
+ },
+
+ init: function() {
+ var $this = this;
+ $this.$dateTimePickers.each(function() {
+ $this.initDateTimePickers(this);
+ });
+ }
+ }
+
+ dateTimePicker.init();
+});
diff --git a/app/assets/javascripts/page_alert.js b/app/assets/javascripts/page_alert.js
new file mode 100644
index 00000000..45c533ed
--- /dev/null
+++ b/app/assets/javascripts/page_alert.js
@@ -0,0 +1,6 @@
+document.addEventListener("turbolinks:load", function(){
+ var $modal = $('#page-alert-modal').modal({
+ show: true
+ });
+});
+
diff --git a/app/assets/javascripts/pages/backend/leave_applications.js b/app/assets/javascripts/pages/backend/leave_applications.js
index 75546f14..406ede1f 100644
--- a/app/assets/javascripts/pages/backend/leave_applications.js
+++ b/app/assets/javascripts/pages/backend/leave_applications.js
@@ -16,14 +16,20 @@ document.addEventListener("turbolinks:load", function() {
Turbolinks.visit("/backend/leave_applications?status=" + status + "&year=" + year );
})
+ //員工休假統計頁
var $statistics_year = $("select[id=year]")
var $statistics_month = $("select[id=month]")
+ var $statistics_role = $("select[id=role]")
$statistics_year.on('change', function() {
- Turbolinks.visit("/backend/leave_applications/statistics?year=" + $statistics_year.val() + "&month=" + $statistics_month.val());
+ Turbolinks.visit("/backend/leave_applications/statistics?year=" + $statistics_year.val() + "&month=" + $statistics_month.val() + "&role=" + $statistics_role.val());
});
$statistics_month.on('change', function() {
- Turbolinks.visit("/backend/leave_applications/statistics?year=" + $statistics_year.val() + "&month=" + $statistics_month.val());
+ Turbolinks.visit("/backend/leave_applications/statistics?year=" + $statistics_year.val() + "&month=" + $statistics_month.val() + "&role=" + $statistics_role.val());
+ });
+
+ $statistics_role.on("change", function() {
+ Turbolinks.visit("/backend/leave_applications/statistics?year=" + $statistics_year.val() + "&month=" + $statistics_month.val() + "&role=" + $statistics_role.val());
});
})
diff --git a/app/assets/javascripts/pages/leave_applications.js b/app/assets/javascripts/pages/leave_applications.js
index 8ec42498..c4576289 100644
--- a/app/assets/javascripts/pages/leave_applications.js
+++ b/app/assets/javascripts/pages/leave_applications.js
@@ -1,57 +1,4 @@
document.addEventListener("turbolinks:load", function() {
- // datetimepicker
- var $dateTimePickerStart = $('#datetimepicker_start');
- var $dateTimePickerEnd = $('#datetimepicker_end');
-
- $dateTimePickerStart.datetimepicker( {
- format: 'YYYY-MM-DD HH:mm',
- disabledTimeIntervals: [[moment({ h: 0 }), moment({ h: 9, m: 29 })], [moment({ h: 18, m: 31 }), moment({ h: 24 })]],
- stepping: 30,
- useCurrent: false,
- sideBySide: true,
- viewDate: moment(new Date()).format('YYYY-MM-DD') + " 09:30",
- });
-
- $dateTimePickerEnd.datetimepicker( {
- format: 'YYYY-MM-DD HH:mm',
- disabledTimeIntervals: [[moment({ h: 0 }), moment({ h: 9, m: 29 })], [moment({ h: 18, m: 31 }), moment({ h: 24 })]],
- stepping: 30,
- useCurrent: false,
- sideBySide: true,
- viewDate: moment(new Date()).format('YYYY-MM-DD') + " 10:30",
- });
-
- var startTimeChangeFirst = false;
- var $startTimeInput = $dateTimePickerStart.find("#leave_application_start_time");
- var $endTimeInput = $dateTimePickerEnd.find("#leave_application_end_time");
-
- $dateTimePickerStart.on( 'dp.change', function(e){
- if ( startTimeChangeFirst == false) {
- startTimeChangeFirst = true;
- }
-
- if (startTimeChangeFirst) {
- var startTime = moment( $startTimeInput.val() );
- var endTime = moment( $endTimeInput.val() );
- var m = startTime.clone().add(1, 'hours');
-
- $dateTimePickerEnd.data('DateTimePicker').minDate(m);
-
- if (startTime > endTime) {
- $dateTimePickerEnd.data('DateTimePicker').date(m);
- }
- }
- });
-
- $dateTimePickerEnd.on( 'dp.change', function(e){
- if (startTimeChangeFirst) {
- var endTime = moment( $endTimeInput.val() );
- var m = endTime.clone().subtract(1, 'hours');
-
- $dateTimePickerStart.data('DateTimePicker').maxDate( m );
- }
- });
-
$year = $("#year");
$leaveStatus = $("#status");
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 604b71c7..41c17f1e 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -4,7 +4,6 @@
@import "bootstrap-sprockets";
@import "bootstrap";
-@import "bootstrap-datetimepicker";
@import "base";
@import "bootstrap_override";
-@import "bootstrap3-datetimepicker";
+@import "flatpickr";
diff --git a/app/assets/stylesheets/pages/backend/leave_applications.scss b/app/assets/stylesheets/pages/backend/leave_applications.scss
index e69de29b..f7daa1e2 100644
--- a/app/assets/stylesheets/pages/backend/leave_applications.scss
+++ b/app/assets/stylesheets/pages/backend/leave_applications.scss
@@ -0,0 +1,3 @@
+.highlight{
+ color: red;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/pages/backend/leave_times.scss b/app/assets/stylesheets/pages/backend/leave_times.scss
index 3c38fe1d..04080da9 100644
--- a/app/assets/stylesheets/pages/backend/leave_times.scss
+++ b/app/assets/stylesheets/pages/backend/leave_times.scss
@@ -4,3 +4,7 @@
text-align: center;
}
}
+
+.checkbox-inline:first-child {
+ margin-left: 10px;
+}
\ No newline at end of file
diff --git a/app/controllers/backend/leave_applications_controller.rb b/app/controllers/backend/leave_applications_controller.rb
index 4079519c..ae82169d 100644
--- a/app/controllers/backend/leave_applications_controller.rb
+++ b/app/controllers/backend/leave_applications_controller.rb
@@ -7,6 +7,16 @@ def index
@users = User.all
end
+ def create
+ @current_object = collection_scope.new(resource_params)
+ if @current_object.save
+ @current_object.approve!(current_user)
+ action_success
+ else
+ render action: :new
+ end
+ end
+
def verify; end
def update
@@ -21,7 +31,11 @@ def update
end
def statistics
- @statistics = LeaveApplication.statistics_table(year: specific_year.to_i, month: specific_month.to_i)
+ @summary = LeaveTimeSummaryService.new(
+ specific_year.to_i,
+ specific_month.to_i,
+ specific_role
+ ).summary
end
private
@@ -36,7 +50,7 @@ def approve
end
def reject
- if current_object.pending?
+ if current_object.pending? or current_object.approved?
current_object.reject!(current_user)
action_success
else
@@ -53,7 +67,10 @@ def collection_scope
end
def resource_params
- params.require(:leave_application).permit(:comment)
+ case action_name
+ when 'create' then params.require(:leave_application).permit(:user_id, :leave_type, :start_time, :end_time, :description, :comment)
+ when 'update' then params.require(:leave_application).permit(:comment)
+ end
end
def search_params
diff --git a/app/controllers/backend/leave_times_controller.rb b/app/controllers/backend/leave_times_controller.rb
index bb7376f5..556a1cb6 100644
--- a/app/controllers/backend/leave_times_controller.rb
+++ b/app/controllers/backend/leave_times_controller.rb
@@ -6,11 +6,41 @@ def index
@users = User.all
end
+ def new
+ @current_object = LeaveTime.new
+ end
+
+ def create
+ @current_object = LeaveTime.new(resource_params)
+ return render action: :new unless @current_object.save
+
+ if request.env['HTTP_REFERER'].include?('leave_application_id')
+ verify_id = request.env['HTTP_REFERER'].partition('=').last
+ action_success(verify_backend_leave_application_path(verify_id))
+ else
+ action_success
+ end
+
+ end
+
def append_quota
@current_object = collection_scope.new(leave_time_params_by_leave_application)
render :new
end
+ def batch_new
+ @current_object = LeaveTime.new
+ end
+
+ def batch_create
+ user_ids = params[:leave_time][:user_id]
+ user_ids.each do |user_id|
+ @current_object = LeaveTime.new(batch_leave_time_params.merge(user_id: user_id))
+ return render action: :batch_new unless @current_object.save
+ end
+ action_success
+ end
+
private
def leave_time_params_by_leave_application
@@ -36,6 +66,11 @@ def resource_params
)
end
+ def batch_leave_time_params
+ params.require(:leave_time).permit(
+ :leave_type, :quota, :effective_date, :expiration_date, :usable_hours, :used_hours, :remark)
+ end
+
def search_params
params.fetch(:q, {})&.permit(:s, :leave_type_eq, :effective_true, :user_id_eq)
end
diff --git a/app/controllers/backend/users_controller.rb b/app/controllers/backend/users_controller.rb
index 3c9838d5..27e1cb2a 100644
--- a/app/controllers/backend/users_controller.rb
+++ b/app/controllers/backend/users_controller.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class Backend::UsersController < Backend::BaseController
before_action :set_query_object
- before_action :set_minimum_password_length, only: %i[new edit]
+ before_action :set_minimum_password_length, only: %i(new edit)
def show
@leave_times = current_object.leave_times
diff --git a/app/controllers/base_controller.rb b/app/controllers/base_controller.rb
index 2d93bade..79ee8b4b 100644
--- a/app/controllers/base_controller.rb
+++ b/app/controllers/base_controller.rb
@@ -48,7 +48,7 @@ def action_fail(message, action)
end
def set_actions
- @actions = [:create, :update, :destroy]
+ @actions = [:create, :update, :destroy, :batch_create]
end
def action_success(url = nil)
@@ -103,4 +103,8 @@ def specific_year
def specific_month
params[:month] || Time.current.month
end
+
+ def specific_role
+ params[:role].empty? ? %w(employee parttime) : params[:role]
+ end
end
diff --git a/app/controllers/leave_applications_controller.rb b/app/controllers/leave_applications_controller.rb
index 39b16b27..f5899dc4 100644
--- a/app/controllers/leave_applications_controller.rb
+++ b/app/controllers/leave_applications_controller.rb
@@ -2,11 +2,12 @@
class LeaveApplicationsController < BaseController
include Selectable
before_action :set_query_object
+ after_action :auto_approve_for_contractor, only: [:create, :update], if: :contractor?
def index
- @current_collection = collection_scope.with_year(specific_year)
+ @current_collection = collection_scope.page(params[:page])
+ @current_collection = Kaminari.paginate_array(@current_collection.first(5)).page(params[:page]) unless query?
@current_collection = @current_collection.with_status(params[:status]) if status_selected?
- @current_collection = @current_collection.page(params[:page])
end
def create
@@ -55,10 +56,13 @@ def collection_scope
end
end
+ def query?
+ !params[:q].nil?
+ end
+
def search_params
@search_params = params.fetch(:q, {})&.permit(
:s, :leave_type_eq, :status_eq, :end_date_gteq, :start_date_lteq)
- @search_params.present? ? @search_params : @search_params.merge(status_eq: :pending)
end
def set_query_object
@@ -73,9 +77,17 @@ def resource_params
def url_after(action)
if @actions.include?(action)
- url_for(action: :index, controller: controller_path, params: { status: :pending })
+ url_for(action: :index, controller: controller_path)
else
request.env['HTTP_REFERER']
end
end
+
+ def auto_approve_for_contractor
+ current_object.approve!(current_user)
+ end
+
+ def contractor?
+ current_user.contractor?
+ end
end
diff --git a/app/controllers/leave_times_controller.rb b/app/controllers/leave_times_controller.rb
index a7632b60..d4bd8ae4 100644
--- a/app/controllers/leave_times_controller.rb
+++ b/app/controllers/leave_times_controller.rb
@@ -2,7 +2,7 @@
class LeaveTimesController < BaseController
STARTING_YEAR = Settings.misc.starting_year.to_i
SHOWINGS = %i(all effective).freeze
- DEFAULT_SHOWING = 'effective'
+ DEFAULT_SHOWING = 'effective'.freeze
before_action :set_query_object
helper_method :showing
@@ -28,6 +28,7 @@ def set_query_object
end
def search_params
- params.fetch(:q, {})&.permit(:s, :leave_type_eq, :effective_true)
+ @search_params = params.fetch(:q, {})&.permit(:s, :leave_type_eq, :effective_true)
+ @search_params.present? ? @search_params : @search_params.merge(effective_true: true)
end
end
diff --git a/app/controllers/remote_controller.rb b/app/controllers/remote_controller.rb
index 8bbc5ef5..4f874811 100644
--- a/app/controllers/remote_controller.rb
+++ b/app/controllers/remote_controller.rb
@@ -2,7 +2,7 @@ class RemoteController < BaseController
skip_load_and_authorize_resource
load_and_authorize_resource class: LeaveApplication
- def create
+ def create
@current_object = collection_scope.new(resource_params)
if @current_object.save
action_success
@@ -11,25 +11,23 @@ def create
end
end
+ private
- private
-
- def collection_scope
- current_user.leave_applications.where(leave_type: :remote)
- end
+ def collection_scope
+ current_user.leave_applications.where(leave_type: :remote)
+ end
- def resource_params
- params.require(:remote_application).permit(
- :start_time, :end_time, :description
- )
- end
+ def resource_params
+ params.require(:remote_application).permit(
+ :start_time, :end_time, :description
+ )
+ end
- def url_after(action)
+ def url_after(action)
if @actions.include?(action)
url_for(controller: :leave_applications, action: :index)
else
request.env['HTTP_REFERER']
end
end
-
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 2b40ff6b..08fd964e 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -81,11 +81,20 @@ def specific_month
params[:month] || Time.current.month
end
+ def specific_role
+ params[:role].empty? ? %w(employee parttime) : params[:role]
+ end
+
def hours_to_humanize(hours)
return '-' if hours.to_i.zero?
I18n.t('time.humanize_working_hour', days: hours.to_i / 8, hours: hours % 8, total: hours)
end
+ def hours_for_total(hours)
+ return '-' if hours.to_i.zero?
+ I18n.t('time.total_hour', total: hours)
+ end
+
def type_selector(name, label, options, default)
render 'shared/type_selector', name: name, label: label, options: options, default: default
end
diff --git a/app/helpers/leave_applications_helper.rb b/app/helpers/leave_applications_helper.rb
index c7fbdb15..a5670713 100644
--- a/app/helpers/leave_applications_helper.rb
+++ b/app/helpers/leave_applications_helper.rb
@@ -23,4 +23,22 @@ def colored_state_label(status)
haml_tag :span, humanize_status, class: 'label label-danger'
end
end
+
+ def need_deduct_salary?(leave_type, leave_time)
+ return if leave_time == 0
+ leave_type == 'personal' || leave_type == 'halfpaid_sick'
+ end
+
+ def summary_from(summary, user_id)
+ leave_types = Settings.leave_times.quota_types.keys
+ summary[user_id] || Hash[leave_types.collect{ |type| [type, 0]}]
+ end
+
+ def leave_type_dropdown_menu(action_name, user)
+ if user.role == 'contractor'
+ LeaveApplication.enum_attributes_for_select(:leave_types, except = [:remote, :sick, :maternity, :marriage, :compassionate, :official, :occpational_sick, :menstrual])
+ else
+ LeaveApplication.enum_attributes_for_select(:leave_types)
+ end
+ end
end
diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb
index 24289009..7548f09d 100644
--- a/app/mailers/application_mailer.rb
+++ b/app/mailers/application_mailer.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
class ApplicationMailer < ActionMailer::Base
- default from: 'from@example.com'
+ default from: 'hi@5xruby.tw'
+
layout 'mailer'
+ prepend_view_path Rails.root.join('app', 'views', 'mailers')
end
diff --git a/app/mailers/information_mailer.rb b/app/mailers/information_mailer.rb
new file mode 100644
index 00000000..eb09bb5b
--- /dev/null
+++ b/app/mailers/information_mailer.rb
@@ -0,0 +1,33 @@
+class InformationMailer < ApplicationMailer
+ ADMIN_EMAIL_LISTS = [
+ 'hi@5xruby.tw'
+ ].freeze
+
+ DEVELOP_EMAIL_LISTS = [
+ 'eileen@5xruby.tw'
+ ].freeze
+
+ def new_application(leave_application)
+ @leave_application = leave_application
+
+ mail(
+ to: receiver_lists,
+ subject: "New Leave Application about #{@leave_application.user.name}"
+ )
+ end
+
+ def cancel_application(leave_application)
+ @leave_application = leave_application
+
+ mail(
+ to: receiver_lists,
+ subject: "#{@leave_application.user.name} just canceled leave application"
+ )
+ end
+
+ private
+
+ def receiver_lists
+ Rails.env.production? ? ADMIN_EMAIL_LISTS : DEVELOP_EMAIL_LISTS
+ end
+end
diff --git a/app/mailers/previews/information_mailer_preview.rb b/app/mailers/previews/information_mailer_preview.rb
new file mode 100644
index 00000000..d2a91682
--- /dev/null
+++ b/app/mailers/previews/information_mailer_preview.rb
@@ -0,0 +1,6 @@
+class InformationMailerPreview < ActionMailer::Preview
+ def new_application
+ test_leave_application = LeaveApplication.last
+ InformationMailer.new_application(test_leave_application)
+ end
+end
diff --git a/app/mailers/previews/user_mailer_preview.rb b/app/mailers/previews/user_mailer_preview.rb
new file mode 100644
index 00000000..c2f034b9
--- /dev/null
+++ b/app/mailers/previews/user_mailer_preview.rb
@@ -0,0 +1,6 @@
+class UserMailerPreview < ActionMailer::Preview
+ def reply_leave_applicaiton_email
+ test_leave_application = LeaveApplication.last
+ UserMailer.reply_leave_applicaiton_email(test_leave_application)
+ end
+end
diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb
new file mode 100644
index 00000000..13ef1caf
--- /dev/null
+++ b/app/mailers/user_mailer.rb
@@ -0,0 +1,16 @@
+class UserMailer < ApplicationMailer
+ def reply_leave_applicaiton_email(leave_application)
+ @leave_application = leave_application
+ if %w(staging development).include?(Rails.env)
+ mail(
+ to: @leave_application.user.email,
+ subject: "[測試信]<請假結果通知> 你的#{LeaveApplication.human_enum_value(:leave_type, @leave_application.leave_type)}已被#{LeaveApplication.human_enum_value(:status, @leave_application.status)}"
+ )
+ else
+ mail(
+ to: @leave_application.user.email,
+ subject: "<請假結果通知> 你的#{LeaveApplication.human_enum_value(:leave_type, @leave_application.leave_type)}已被#{LeaveApplication.human_enum_value(:status, @leave_application.status)}"
+ )
+ end
+ end
+end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 9645a214..77d4f529 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -7,9 +7,11 @@ def initialize(user)
case user.role
when 'manager', 'hr'
can :manage, :all
- when 'employee'
+ when 'employee', 'parttime', 'intern'
can :read, LeaveTime, user_id: user.id
can :manage, LeaveApplication, user_id: user.id
+ when 'contractor'
+ can :manage, LeaveApplication, user_id: user.id
end
end
end
diff --git a/app/models/leave_application.rb b/app/models/leave_application.rb
index 3503cd93..3d62859c 100644
--- a/app/models/leave_application.rb
+++ b/app/models/leave_application.rb
@@ -29,7 +29,7 @@ class LeaveApplication < ApplicationRecord
)
}
- scope :personal, ->(user_id, beginning, ending, status_array = %w[pending approved]) {
+ scope :personal, ->(user_id, beginning, ending, status_array = %w(pending approved)) {
where(status: status_array, user_id: user_id).leave_within_range(beginning, ending)
}
@@ -59,11 +59,11 @@ class LeaveApplication < ApplicationRecord
end
event :reject, before: proc { |manager| sign(manager) } do
- transitions to: :rejected, from: :pending
+ transitions to: :rejected, from: %i(pending approved)
end
event :revise do
- transitions to: :pending, from: %i[pending approved]
+ transitions to: :pending, from: %i(pending approved)
end
event :cancel do
@@ -94,7 +94,7 @@ def aasm_event?(event)
end
def special_type?
- %w(marriage compassionate official maternity).include? self.leave_type
+ %w(marriage compassionate official maternity occpational_sick menstrual paid_vacation).include? self.leave_type
end
def available_leave_times
@@ -114,7 +114,7 @@ def leave_time_params
{
user_id: self.user_id,
leave_type: self.leave_type,
- effective_date: self.start_time.to_date,
+ effective_date: self.start_time.to_date
}
end
diff --git a/app/models/leave_application_observer.rb b/app/models/leave_application_observer.rb
index 613175c1..6d753107 100644
--- a/app/models/leave_application_observer.rb
+++ b/app/models/leave_application_observer.rb
@@ -16,7 +16,8 @@ def after_save(record)
def after_create(record)
create_leave_time_usages(record)
- FlowdockService.new(leave_application: record).send_create_notification
+ FlowdockService.new(leave_application: record).send_create_notification if Rails.env.production?
+ InformationMailer.new_application(record).deliver_later if Rails.env.production?
end
def before_update(record)
@@ -25,7 +26,9 @@ def before_update(record)
def after_update(record)
create_leave_time_usages(record) if record.aasm_event?(:revise)
- FlowdockService.new(leave_application: record).send_update_notification(record.aasm.to_state)
+ FlowdockService.new(leave_application: record).send_update_notification(record.aasm.to_state) if Rails.env.production?
+ UserMailer.reply_leave_applicaiton_email(record).deliver_later if record.aasm_event?(:approve) or record.aasm_event?(:reject)
+ InformationMailer.cancel_application(record).deliver_later if record.aasm_event?(:cancel) && Rails.env.production?
end
private
@@ -47,7 +50,7 @@ def create_leave_hours_by_date(record)
end
def create_leave_time_usages(record)
- raise ActiveRecord::Rollback if not LeaveTimeUsageBuilder.new(record).build_leave_time_usages and not record.special_type?
+ raise ActiveRecord::Rollback if !LeaveTimeUsageBuilder.new(record).build_leave_time_usages and !record.special_type?
end
def hours_transfer(record)
@@ -65,21 +68,13 @@ def transfer_locked_hours_to_used_hours(record)
def return_leave_time_usable_hours(record)
record.leave_time_usages.each { |usage| revert_hours(record, usage) }
- record.leave_time_usages.delete_all
- end
-
- def revert_used_hours_to_usable_hours(record)
- record.leave_time_usages.each { |usage| usage.leave_time.unuse_hours!(usage.used_hours) }
- record.leave_time_usages.delete_all
+ record.leave_time_usages.destroy_all
end
def revert_hours(record, usage)
- if record.aasm.from_state == :pending
- usage.leave_time.unlock_hours!(usage.used_hours)
- elsif record.aasm.from_state == :approved
- usage.leave_time.unuse_hours!(usage.used_hours)
- else
- raise ActiveRecord::Rollback
- end
+ usage.reload
+ return usage.leave_time.unlock_hours!(usage.used_hours) if record.aasm.from_state == :pending
+ return usage.leave_time.unuse_hours!(usage.used_hours) if record.aasm.from_state == :approved
+ raise ActiveRecord::Rollback
end
-end
\ No newline at end of file
+end
diff --git a/app/models/leave_time.rb b/app/models/leave_time.rb
index 13b1737a..1c31c9ef 100644
--- a/app/models/leave_time.rb
+++ b/app/models/leave_time.rb
@@ -54,7 +54,7 @@ def cover?(time_format)
end
def special_type?
- %w(marriage compassionate official maternity).include? self.leave_type
+ %w(marriage compassionate official maternity occpational_sick menstrual).include? self.leave_type
end
def lock_hours(hours)
diff --git a/app/models/leave_time_usage.rb b/app/models/leave_time_usage.rb
index 32dddc73..9f07b697 100644
--- a/app/models/leave_time_usage.rb
+++ b/app/models/leave_time_usage.rb
@@ -8,6 +8,6 @@ class LeaveTimeUsage < ApplicationRecord
private
def transfer_leave_time_hours
- self.leave_time.reload.lock_hours!(self.used_hours)
+ self.leave_time.reload.lock_hours!(self.used_hours)
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 0937498a..04609718 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -34,21 +34,26 @@ class User < ApplicationRecord
scope :valid, -> {
where('join_date <= :now', now: Date.current)
- .where.not(role: %w[pending resigned])
+ .where.not(role: %w(pending resigned))
}
scope :fulltime, -> {
- where('role in (?)', %w[manager employee hr])
+ where('role in (?)', %w(manager employee hr))
.valid
.order(id: :desc)
}
scope :parttime, -> {
- where('role in (?)', %w[contractor intern])
+ where('role in (?)', %w(contractor intern))
.valid
.order(id: :desc)
}
+ scope :filter_by_role, ->(role) {
+ where(role: role)
+ .order(id: :desc)
+ }
+
Settings.roles.each do |key, role|
define_method "is_#{role}?" do
self.role.to_s == role
@@ -61,7 +66,7 @@ def seniority(time = Date.current)
end
def fulltime?
- %w[manager hr employee].include?(role)
+ %w(manager hr employee).include?(role)
end
def this_year_join_anniversary
diff --git a/app/services/flowdock_service.rb b/app/services/flowdock_service.rb
index 58d44b65..7ac372a9 100644
--- a/app/services/flowdock_service.rb
+++ b/app/services/flowdock_service.rb
@@ -4,7 +4,7 @@ class FlowdockService
attr_accessor :leave_application
- def initialize(attributes={})
+ def initialize(attributes = {})
super
@flow_token_client = Flowdock::Client.new(flow_token: Settings.flowdock.token)
end
@@ -14,45 +14,45 @@ def send_create_notification
subject: "#{leave_application.user.name} 新增了一筆 #{LeaveApplication.human_enum_value(:leave_type, leave_application.leave_type)} 假單",
content: (LeaveApplicationsController.render partial: 'leave_applications/notification', locals: { leave_application: leave_application }),
url: verify_backend_leave_application_url(id: leave_application),
- color: "green",
- value: "Create",
+ color: 'green',
+ value: 'Create',
thread_id: leave_application.id
)
end
def send_update_notification(event)
return if event.blank?
- executer = %i[canceled pending].include?(event) ? leave_application.user : leave_application.manager
+ executer = %i(canceled pending).include?(event) ? leave_application.user : leave_application.manager
notify(
subject: "#{executer.name} #{LeaveApplication.human_enum_value(:modify_actions, event)}了一筆 #{leave_application.user.name} 的 #{LeaveApplication.human_enum_value(:leave_type, leave_application.leave_type)} 假單",
content: (LeaveApplicationsController.render partial: 'leave_applications/notification', locals: { leave_application: leave_application }),
url: verify_backend_leave_application_url(id: leave_application),
- color: "yellow",
- value: "Update",
+ color: 'yellow',
+ value: 'Update',
thread_id: leave_application.id
)
end
private
- def notify(subject: , content: , url: , color: , value: , thread_id:)
+ def notify(subject:, content:, url:, color:, value:, thread_id:)
@flow_token_client.post_to_thread(
- event: "activity",
- author: {
- name: "Daikichi",
- avatar: "http://i.imgur.com/ycz7jqg.png",
- },
- title: "5xRuby",
- external_thread_id: thread_id,
- thread: {
+ event: 'activity',
+ author: {
+ name: 'Daikichi',
+ avatar: 'http://i.imgur.com/ycz7jqg.png'
+ },
+ title: '5xRuby',
+ external_thread_id: thread_id,
+ thread: {
title: subject,
body: content,
external_url: url,
status: {
- color: color,
- value: value
+ color: color,
+ value: value
}
}
)
- end
-end
\ No newline at end of file
+ end
+end
diff --git a/app/services/leave_time_batch_builder.rb b/app/services/leave_time_batch_builder.rb
index 1d5ac345..cda874b3 100644
--- a/app/services/leave_time_batch_builder.rb
+++ b/app/services/leave_time_batch_builder.rb
@@ -10,20 +10,16 @@ def initialize(forced: false)
def automatically_import
batch_join_date_based_import
batch_monthly_import
+ batch_weekly_import
end
private
def batch_join_date_based_import
leed_day = Time.current + JOIN_DATE_BASED_LEED_DAYS.days
- users = if @forced
- User.valid.where('(EXTRACT(MONTH FROM join_date), EXTRACT(DAY FROM join_date)) <= (:month, :date)', month: leed_day.month, date: leed_day.day)
- .where.not(join_date: ((Time.current - 1.year).to_date)..(Time.current))
- else
- User.valid.filter_by_join_date(reaching_join_date.month, reaching_join_date.day)
- end
- return unless users.present?
- users.find_each do |user|
+ find_user_by_forced(User.valid, leed_day)
+ return if @users.empty?
+ @users.each do |user|
if @forced
LeaveTimeBuilder.new(user).join_date_based_import
else
@@ -43,6 +39,17 @@ def batch_monthly_import
end
end
+ def batch_weekly_import
+ return if !Time.current.monday? && !@forced
+ User.valid.find_each do |user|
+ if @forced
+ LeaveTimeBuilder.new(user).weekly_import
+ else
+ LeaveTimeBuilder.new(user).weekly_import(prebuild: true)
+ end
+ end
+ end
+
def end_of_working_month?
@end_of_working_month_bool ||= Daikichi::Config::Biz.time(MONTHLY_LEED_DAYS, :days).after(Time.current.beginning_of_day).to_date == Daikichi::Config::Biz.periods.before(Time.current.end_of_month).first.end_time.to_date
end
@@ -50,4 +57,13 @@ def end_of_working_month?
def reaching_join_date
@reaching_join_date ||= Time.zone.today + JOIN_DATE_BASED_LEED_DAYS.days
end
+
+ def find_user_by_forced(valid_users, leed_day)
+ if @forced
+ @users = []
+ valid_users.where.not(join_date: (Time.current.to_date)..(Time.current)).find_each.map { |user| @users << user if user.this_year_join_anniversary - leed_day.to_date <= 60 }
+ else
+ @users = valid_users.filter_by_join_date(reaching_join_date.month, reaching_join_date.day)
+ end
+ end
end
diff --git a/app/services/leave_time_builder.rb b/app/services/leave_time_builder.rb
index 0f8a766f..53ca89bf 100644
--- a/app/services/leave_time_builder.rb
+++ b/app/services/leave_time_builder.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
class LeaveTimeBuilder
MONTHLY_LEAVE_TYPES = Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'monthly' }
+ WEEKLY_LEAVE_TYPES = Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'weekly' }
JOIN_DATE_BASED_LEAVE_TYPES = Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'join_date_based' }
JOIN_DATE_BASED_LEED_DAY = Settings.leed_days.join_date_based.day
@@ -11,23 +12,35 @@ def initialize(user)
def automatically_import(by_assign_date: false)
monthly_import by_assign_date: by_assign_date
join_date_based_import by_assign_date: by_assign_date
+ weekly_import by_assign_date: by_assign_date
end
def join_date_based_import(by_assign_date: false, prebuild: false)
+ return create_leave_time('personal', 2920, @user.join_date, @user.join_date.next_year) if @user.role == 'contractor'
JOIN_DATE_BASED_LEAVE_TYPES.each do |leave_type, config|
- build_join_date_based_leave_types(leave_type, config, by_assign_date, prebuild)
+ build_join_date_based_leave_types(leave_type, config, prebuild, by_assign_date)
end
end
def monthly_import(by_assign_date: false, prebuild: false)
+ return if @user.role == 'contractor'
MONTHLY_LEAVE_TYPES.each do |leave_type, config|
- build_monthly_leave_types(leave_type, config, by_assign_date, prebuild)
+ build_monthly_leave_types(leave_type, config, prebuild, by_assign_date)
+ end
+ end
+
+ def weekly_import(by_assign_date: false, prebuild: false)
+ return if @user.role == 'contractor'
+ return unless by_assign_date || Time.current.monday?
+ date = Time.zone.today + 4.weeks
+ WEEKLY_LEAVE_TYPES.each do |leave_type, config|
+ build_weekly_leave_types(leave_type, config, date, by_assign_date)
end
end
private
- def build_join_date_based_leave_types(leave_type, config, build_by_assign_date = false, prebuild)
+ def build_join_date_based_leave_types(leave_type, config, prebuild, build_by_assign_date = false)
return unless user_can_have_leave_type?(@user, config)
quota = extract_quota(config, @user, prebuild: prebuild)
if build_by_assign_date
@@ -60,7 +73,7 @@ def join_date_based_by_assign_date(leave_type, quota)
create_leave_time(leave_type, quota, date, expiration_date) if Time.zone.now.to_date + JOIN_DATE_BASED_LEED_DAY >= date or @user.join_date + 1.year >= Time.zone.now.to_date
end
- def build_monthly_leave_types(leave_type, config, build_by_assign_date = false, prebuild)
+ def build_monthly_leave_types(leave_type, config, prebuild, build_by_assign_date = false)
quota = extract_quota(config, @user, prebuild: prebuild)
if build_by_assign_date
date = @user.assign_date >= @user.join_date ? @user.assign_date : @user.join_date
@@ -76,6 +89,22 @@ def build_monthly_leave_types(leave_type, config, build_by_assign_date = false,
end
end
+ def build_weekly_leave_types(leave_type, config, date, build_by_assign_date)
+ quota = extract_quota(config, @user)
+ if build_by_assign_date
+ effective_date = @user.assign_date
+ expiration_date = @user.assign_date.end_of_week
+ create_leave_time(leave_type, quota, effective_date, expiration_date)
+ create_leave_time(leave_type, quota, effective_date.beginning_of_week + 1.week, expiration_date + 1.week)
+ create_leave_time(leave_type, quota, effective_date.beginning_of_week + 2.week, expiration_date + 2.week)
+ create_leave_time(leave_type, quota, effective_date.beginning_of_week + 3.week, expiration_date + 3.week)
+ else
+ effective_date = date.beginning_of_week
+ expiration_date = date.end_of_week
+ create_leave_time(leave_type, quota, effective_date, expiration_date)
+ end
+ end
+
def create_leave_time(leave_type, quota, effective_date, expiration_date)
@user.leave_times.create(
leave_type: leave_type,
diff --git a/app/services/leave_time_summary_service.rb b/app/services/leave_time_summary_service.rb
new file mode 100644
index 00000000..bee63d98
--- /dev/null
+++ b/app/services/leave_time_summary_service.rb
@@ -0,0 +1,49 @@
+class LeaveTimeSummaryService
+ def initialize(year, month, role = %w(employee parttime))
+ @range = (
+ Time.zone.local(year, month).beginning_of_month..
+ Time.zone.local(year, month).end_of_month
+ )
+ @types = Settings.leave_times.quota_types.keys
+ @role = role
+ end
+
+ def user_applications
+ @user_applications ||= LeaveApplication.where(user: User.filter_by_role(@role)).leave_within_range(@range.min, @range.max)
+ .approved
+ .includes(:leave_time_usages, :leave_times)
+ .group_by(&:user_id)
+ end
+
+ def application_to_usage(applications)
+ applications.map(&:leave_time_usages)
+ .flatten
+ .group_by { |usage| usage.leave_time.leave_type }
+ .map { |k, v| [k, used_hours_in_month(v).sum] }
+ end
+
+ def summary
+ @summary ||= Hash[
+ user_applications.map do |(id, applications)|
+ [
+ id,
+ default_columns.merge(Hash[application_to_usage(applications)])
+ ]
+ end
+ ]
+ end
+
+ private
+
+ def default_columns
+ Hash[@types.collect { |type| [type, 0] }]
+ end
+
+ def used_hours_in_month(usages)
+ usages_in_month(usages).map(&:used_hours)
+ end
+
+ def usages_in_month(usages)
+ usages.select { |usage| usage.date.between? @range.min, @range.max }
+ end
+end
diff --git a/app/services/leave_time_usage_builder.rb b/app/services/leave_time_usage_builder.rb
index 1c7e515c..8a785036 100644
--- a/app/services/leave_time_usage_builder.rb
+++ b/app/services/leave_time_usage_builder.rb
@@ -19,15 +19,16 @@ def build_leave_time_usages
@available_leave_times.each do |lt|
@leave_hours_by_date.keys.each do |date|
+ hours = @leave_hours_by_date[date]
break if usable_hours_is_empty?(lt)
- next if corresponding_leave_hours_date_is_zero?(date) or not in_leave_time_inteval_range?(lt, date)
+ next if corresponding_leave_hours_date_is_zero?(date) or !in_leave_time_inteval_range?(lt, date)
deduct_leave_hours_by_date(lt, date)
+ stack_leave_time_usage_record(lt, date, hours - @leave_hours_by_date[date])
end
- stack_leave_time_usage_record(lt)
break if leave_hours_by_date_is_empty?
end
- if not leave_hours_by_date_is_empty?
+ if !leave_hours_by_date_is_empty?
rollback_with_error_message unless @leave_application.special_type?
else
create_leave_time_usage
@@ -53,7 +54,6 @@ def validate_application_covered_by_leave_time_interval
include_end_time = true if lt.cover?(@leave_hours_by_date.keys.last)
break if include_start_time && include_end_time
end
-
rollback_with_error_message unless include_start_time && include_end_time
end
@@ -79,17 +79,14 @@ def in_leave_time_inteval_range?(leave_time, date)
date.between?(leave_time.effective_date, leave_time.expiration_date)
end
- def stack_leave_time_usage_record(leave_time)
- @leave_time_usages.push(leave_time: leave_time, used_hours: leave_time.usable_hours_was - leave_time.usable_hours)
+ def stack_leave_time_usage_record(leave_time, date, used_hours)
+ @leave_time_usages.push(leave_time: leave_time, used_hours: used_hours, date: date)
end
def leave_hours_by_date_is_empty?
@leave_hours_by_date.values.all?(&:zero?)
end
- def unless_remain_leave_hours_by_date
- end
-
def rollback_with_error_message
append_leave_application_error_message
raise ActiveRecord::Rollback
@@ -102,7 +99,7 @@ def append_leave_application_error_message
def create_leave_time_usage
@leave_time_usages.each do |lt_usage|
- @leave_application.leave_time_usages.create!(leave_time: lt_usage[:leave_time], used_hours: lt_usage[:used_hours])
+ @leave_application.leave_time_usages.create!(leave_time: lt_usage[:leave_time], used_hours: lt_usage[:used_hours], date: lt_usage[:date])
end
end
end
diff --git a/app/views/backend/leave_applications/_form.html.haml b/app/views/backend/leave_applications/_form.html.haml
index 2b6a4668..b2cdf7bc 100644
--- a/app/views/backend/leave_applications/_form.html.haml
+++ b/app/views/backend/leave_applications/_form.html.haml
@@ -1,6 +1,21 @@
-= simple_form_for current_object, url: backend_leave_application_path(current_object), method: :put do |f|
- = f.input :comment
- = f.button :submit, t("title.backend/leave_applications.approve"), disabled: !current_object.may_approve?, name: "approve", class: "btn btn-primary"
- = f.button :submit, t("title.backend/leave_applications.reject"), name: "reject", class: "btn btn-danger"
- - if current_object.special_type? and not current_object.may_approve?
- = link_to t("title.backend/leave_applications.append_quota"), append_quota_backend_leave_times_path(leave_application_id: current_object), method: :post, class: 'btn btn-warning'
+- if action == :verify
+ = simple_form_for current_object, url: backend_leave_application_path(current_object), method: :put do |f|
+ = f.input :comment
+ = f.button :submit, t("title.backend/leave_applications.approve"), disabled: !current_object.may_approve?, name: "approve", class: "btn btn-primary"
+ = f.button :submit, t("title.backend/leave_applications.reject"), name: "reject", class: "btn btn-danger"
+ - if current_object.special_type? and not current_object.may_approve?
+ = link_to t("title.backend/leave_applications.append_quota"), append_quota_backend_leave_times_path(leave_application_id: current_object), method: :post, class: 'btn btn-warning'
+
+- elsif action == :create
+ %h2= t("captions.backend/leave_applications.#{action_name}")
+ %p= t("captions.backend/leave_applications.#{action_name}/hint")
+ = simple_form_for current_object, url: url_for(action: action), method: :post do |f|
+ = f.association :user, collection: User.where.not(role: 'resigned'), label_method: :name, value_method: :id, required: true
+ = f.error :base, error: sanitize(f.object.errors[:base].join('
'), tags: %w(a br), attributes: %w(href target))
+ = f.input :leave_type, required: true, collection: LeaveApplication.enum_attributes_for_select(:leave_types)
+ = f.input :start_time, as: :string, input_html: { data: { input: 'datetimepicker', format: 'Y/m/d H:i' } }
+ = f.input :end_time, as: :string, input_html: { data: { input: 'datetimepicker', format: 'Y/m/d H:i' } }
+ = f.error :hours, error: sanitize(f.object.errors[:hours].join('
'), tags: %w(br))
+ = f.input :description, required: true
+ = f.input :comment
+ = f.button :submit, class: "submit"
diff --git a/app/views/backend/leave_applications/index.html.haml b/app/views/backend/leave_applications/index.html.haml
index 53a8a376..dbcf8db3 100644
--- a/app/views/backend/leave_applications/index.html.haml
+++ b/app/views/backend/leave_applications/index.html.haml
@@ -13,9 +13,9 @@
include_blank: t('.plz_select_user'), label_method: :name, value_method: :id,
wrapper_html: { class: 'col-md-4' }
= f.input :end_date_gteq, wrapper_html: { class: 'date-input col-md-6' },
- input_html: { data: { input: 'datepicker', format: 'YYYY/MM/DD' } }, required: false
+ input_html: { data: { input: 'datepicker', format: 'Y/m/d' } }, required: false
= f.input :start_date_lteq, wrapper_html: { class: 'date-input col-md-6' },
- input_html: { data: { input: 'datepicker', format: 'YYYY/MM/DD' } }, required: false
+ input_html: { data: { input: 'datepicker', format: 'Y/m/d' } }, required: false
.text-right
= f.button :submit, class: 'btn-warning'
diff --git a/app/views/backend/leave_applications/new.html.haml b/app/views/backend/leave_applications/new.html.haml
new file mode 100644
index 00000000..2c587d9e
--- /dev/null
+++ b/app/views/backend/leave_applications/new.html.haml
@@ -0,0 +1 @@
+= render "form", action: :create
\ No newline at end of file
diff --git a/app/views/backend/leave_applications/statistics.html.haml b/app/views/backend/leave_applications/statistics.html.haml
index 8aa5535c..59cdf0ec 100644
--- a/app/views/backend/leave_applications/statistics.html.haml
+++ b/app/views/backend/leave_applications/statistics.html.haml
@@ -1,44 +1,41 @@
-%h2= t("captions.backend/leave_applications.statistics", year: specific_year, month: specific_month)
+%h2= t("captions.backend/leave_applications.statistics", year: specific_year, month: specific_month, role: params[:role])
.panel.panel-default
.panel-body
.year-mon-selector
.row
- .col-md-6.col-sm-6.col-xs-12
+ .col-md-4.col-sm-4.col-xs-12
.form-group
%label{:for=>"year"} Year
= select_tag "year",
options_for_select(2016 .. Time.now.year, specific_year),
class: "form-control"
- .col-md-6.col-sm-6.col-xs-12
+ .col-md-4.col-sm-4.col-xs-12
.form-group
%label{:for=>"month"} Month
= select_tag "month", options_for_select(1..12, specific_month),
class: "form-control"
+ .col-md-4.col-sm-4.col-xs-12
+ .form-group
+ %label{:for=>"role"} Role
+ = select_tag "role", options_for_select(User.enum_attributes_for_select(:roles), params[:role]),
+ include_blank:true, class: "form-control"
-- if @statistics.columns[0].present?
- %table.table.table-striped.table-bordered.table-hover
- %thead
- %tr.info
- %th.text-center.name= t_attribute(:name, User)
- - @statistics.columns.each do |leave_type|
- %th.text-right= LeaveTime.human_enum_value(:leave_type, leave_type.header)
- %th.text-right 總計
-
- %tbody
- - @statistics.rows.each do |sum|
- %tr
- %td.text-center.name= sum.header
- - sum.data.each do |data|
- - if data.present?
- %td.text-right= hours_to_humanize data.sum
- - else
- %td.text-right -
- %td.text-right= hours_to_humanize sum.total
-
-- else
- = no_data_alert
+%table.table.table-striped.table-bordered.table-hover
+ %thead
+ %tr.info
+ %th.text-center.name= t_attribute(:name, User)
+ - Settings.leave_times.quota_types.keys.each do |leave_type|
+ %th.text-right= t("activerecord.attributes.leave_time.leave_types.#{leave_type}")
+ %th.text-right 總計
+ %tbody
+ - User.filter_by_role(specific_role).find_each do |user|
+ %tr
+ %td.text-center.name= user.name
+ - summary_from(@summary, user.id).each do |key, value|
+ %td.text-right{ class: ('highlight' if need_deduct_salary?(key, value)) }= hours_for_total value
+ %td.text-right= hours_to_humanize summary_from(@summary, user.id).values.sum
diff --git a/app/views/backend/leave_applications/verify.html.haml b/app/views/backend/leave_applications/verify.html.haml
index 6f347c82..55b4b408 100644
--- a/app/views/backend/leave_applications/verify.html.haml
+++ b/app/views/backend/leave_applications/verify.html.haml
@@ -3,6 +3,11 @@
%h4.panel-title= t("captions.backend/leave_applications.verify")
%table.table
+
+ %tr
+ %th= t_attribute :user, LeaveApplication
+ %td= current_object.user_name
+
%tr
%th= t_attribute(:leave_type, current_object)
%td= LeaveTime.human_enum_value(:leave_types, current_object.leave_type)
@@ -50,6 +55,7 @@
%tr
%th.text-right #
%th.text-center 假別
+ %th.text-right 日期
%th.text-right 使用時數
%th.text-right 餘額
%th.text-right 生效日期
@@ -59,11 +65,13 @@
%tr
%td.text-right= link_to usage.leave_time_id, backend_leave_time_path(usage.leave_time_id)
%td.text-center= LeaveTime.human_enum_value(:leave_type, usage.leave_time.leave_type)
+ %td.text-right= usage.date
+
%td.text-right= hours_to_humanize usage.used_hours
%td.text-right= hours_to_humanize usage.leave_time.usable_hours
%td.text-right= l usage.leave_time.effective_date, format: :detailed
%td.text-right= l usage.leave_time.expiration_date, format: :detailed
-- if current_object.pending?
- = render "form"
+- if current_object.pending? or current_object.approved?
+ = render "form", action: :verify
\ No newline at end of file
diff --git a/app/views/backend/leave_times/_form.html.haml b/app/views/backend/leave_times/_form.html.haml
index db80eb15..e1d31925 100644
--- a/app/views/backend/leave_times/_form.html.haml
+++ b/app/views/backend/leave_times/_form.html.haml
@@ -1,13 +1,13 @@
%h2= t("captions.backend/leave_times.#{action_name}")
= simple_form_for [:backend, current_object] do |f|
- = f.association :user, required: true
+ = f.association :user, required: true, collection: User.where.not(role: 'resigned')
= f.input :leave_type, required: true, collection: LeaveTime.enum_attributes_for_select(:leave_types)
= f.input :quota
= f.input :effective_date, as: :string, required: true, wrapper_html: { class: 'date-input' },
- input_html: { data: { input: 'datepicker', format: 'YYYY/MM/DD' } }
+ input_html: { data: { input: 'datepicker', format: 'Y/m/d' } }
= f.input :expiration_date, as: :string, required: true, wrapper_html: { class: 'date-input' },
- input_html: { data: { input: 'datepicker', format: 'YYYY/MM/DD' } }
+ input_html: { data: { input: 'datepicker', format: 'Y/m/d' } }
= f.input :remark, as: :text
- unless current_object.new_record?
= f.input :usable_hours
diff --git a/app/views/backend/leave_times/batch_new.html.haml b/app/views/backend/leave_times/batch_new.html.haml
new file mode 100644
index 00000000..5e8f9042
--- /dev/null
+++ b/app/views/backend/leave_times/batch_new.html.haml
@@ -0,0 +1,16 @@
+%h2= t("captions.backend/leave_times.#{action_name}")
+
+= simple_form_for current_object, url: batch_create_backend_leave_times_path do |f|
+ = f.association :user, required: true, collection: User.where.not(role: 'resigned'),as: :check_boxes, include_hidden: false, item_wrapper_class: "checkbox-inline", label: false
+ = f.input :leave_type, required: true, collection: LeaveTime.enum_attributes_for_select(:leave_types)
+ = f.input :quota
+ = f.input :effective_date, as: :string, required: true, wrapper_html: { class: 'date-input' },
+ input_html: { data: { input: 'datepicker', format: 'Y/m/d' } }
+ = f.input :expiration_date, as: :string, required: true, wrapper_html: { class: 'date-input' },
+ input_html: { data: { input: 'datepicker', format: 'Y/m/d' } }
+ = f.input :remark, as: :text
+ - unless current_object.new_record?
+ = f.input :usable_hours
+ = f.input :used_hours
+ = link_to t("title.backend/leave_times.delete"), backend_leave_time_path(current_object), method: :delete, class: "btn btn-sm btn-danger", data: {confirm: "Are you sure?"}
+ = f.button :submit
diff --git a/app/views/backend/leave_times/show.html.haml b/app/views/backend/leave_times/show.html.haml
index dd280529..21b453f0 100644
--- a/app/views/backend/leave_times/show.html.haml
+++ b/app/views/backend/leave_times/show.html.haml
@@ -45,18 +45,19 @@
%th.text-right= t_attribute :start_time, LeaveApplication
%th.text-right= t_attribute :end_time, LeaveApplication
%tbody
- - current_object.leave_time_usages.each do |usage|
+ - current_object.leave_time_usages.group_by(&:leave_application).each do |usage|
%tr
%td.text-right
- = link_to usage.leave_application_id, verify_backend_leave_application_path(usage.leave_application_id)
- %td.text-center= LeaveApplication.human_enum_value(:leave_type, usage.leave_application.leave_type)
- %td.text-right= usage.leave_application.pending? ? hours_to_humanize(usage.used_hours) : '-'
- %td.text-right= usage.leave_application.approved? ? hours_to_humanize(usage.used_hours) : '-'
- %td.text-right= hours_to_humanize usage.leave_application.hours
+ = link_to usage[0].id, verify_backend_leave_application_path(usage[0])
+ %td.text-center= LeaveApplication.human_enum_value(:leave_type, usage[0].leave_type)
+ %td.text-right= usage[0].pending? ? hours_to_humanize(usage[1].sum(&:used_hours)) : '-'
+ %td.text-right= usage[0].approved? ? hours_to_humanize(usage[1].sum(&:used_hours)) : '-'
+ %td.text-right= hours_to_humanize usage[0].hours
%td.text-center
- - colored_state_label(usage.leave_application.status)
- %td.text-right= l usage.leave_application.start_time, format: :long
- %td.text-right= l usage.leave_application.end_time, format: :long
+ - colored_state_label(usage[0].status)
+ %td.text-right= l usage[0].start_time, format: :long
+ %td.text-right= l usage[0].end_time, format: :long
+
%tr
%th.active.text-right{colspan: 2}= t('.sum')
%td.text-right= hours_to_humanize current_object.leave_time_usages.select { |u| u.leave_application.pending? }.sum(&:used_hours)
diff --git a/app/views/backend/users/_form.html.haml b/app/views/backend/users/_form.html.haml
index c2edd44c..009fbb87 100644
--- a/app/views/backend/users/_form.html.haml
+++ b/app/views/backend/users/_form.html.haml
@@ -5,14 +5,14 @@
= f.input :login_name, required: true
= f.input :email, required: true
= f.input :join_date, as: :string, required: true, wrapper_html: { class: 'date-input' },
- input_html: { data: { input: 'datepicker', format: 'YYYY/MM/DD' } }
+ input_html: { data: { input: 'datepicker', format: 'Y/m/d' } }
= f.input :leave_date, as: :string, wrapper_html: { class: 'date-input' },
- input_html: { data: { input: 'datepicker', format: 'YYYY/MM/DD' } }
+ input_html: { data: { input: 'datepicker', format: 'Y/m/d' } }
- if %w(new create).include? action_name
= f.input :assign_leave_time, as: :boolean
= f.input :assign_date, wrapper_html: { class: 'date-input' },
- input_html: { data: { input: 'datepicker', format: 'YYYY/MM/DD' } }
+ input_html: { data: { input: 'datepicker', format: 'Y/m/d' } }
= f.input :password, required: true, hint: ("密碼長度須 #{@minimum_password_length} 字以上" if @minimum_password_length)
= f.input :password_confirmation, required: true
- else
diff --git a/app/views/backend/users/index.html.haml b/app/views/backend/users/index.html.haml
index c034d01f..a97e5dbe 100644
--- a/app/views/backend/users/index.html.haml
+++ b/app/views/backend/users/index.html.haml
@@ -16,7 +16,7 @@
wrapper_html: { class: 'col-md-4' }, label: t('.id_eq')
= f.input :role_eq, collection: User.enum_attributes_for_select(:roles), required: false,
include_blank: t('.plz_select_role'), wrapper_html: { class: 'col-md-4' },label: t('.role_eq')
-
+
.text-right
= f.button :submit, class: 'btn-warning'
@@ -39,17 +39,20 @@
%tbody
- current_collection.each do |user|
- %tr
- %td.text-right= user.id
- %td.text-center= user.name
- %td.text-center= user.login_name
- %td.text-center= user.email
- %td.text-center= User.human_enum_value(:role, user.role)
- %td.text-right= l user.join_date, format: :detailed
- %td.text-center
- = link_to t("title.backend/users.show"),
- backend_user_path(user),
- class: "btn btn-primary"
- = link_to t("title.backend/users.edit"),
- edit_backend_user_path(user),
- class: "btn btn-warning"
+ - unless user.role == 'resigned'
+ %tr
+ %td.text-right= user.id
+ %td.text-center= user.name
+ %td.text-center= user.login_name
+ %td.text-center= user.email
+ %td.text-center= User.human_enum_value(:role, user.role)
+ %td.text-right= l user.join_date, format: :detailed
+ %td.text-center
+ = link_to t("title.backend/users.show"),
+ backend_user_path(user),
+ class: "btn btn-primary"
+ = link_to t("title.backend/users.edit"),
+ edit_backend_user_path(user),
+ class: "btn btn-warning"
+.paginate
+ = paginate current_collection
diff --git a/app/views/backend/users/show.html.haml b/app/views/backend/users/show.html.haml
index ef13cb7f..4afde2ea 100644
--- a/app/views/backend/users/show.html.haml
+++ b/app/views/backend/users/show.html.haml
@@ -14,11 +14,11 @@
%td.col-md-9= User.human_enum_value(:roles, current_object.role)
%tr
%th.col-md-3= t_attribute(:join_date, User)
- %td.col-md-9= l current_object.join_date, format: :long
+ %td.col-md-9= l current_object.join_date, format: :default
- if current_object.leave_date
%tr
%th.col-md-3= t_attribute(:leave_date, User)
- %td.col-md-9= l current_object.leave_date, format: :long
+ %td.col-md-9= l current_object.leave_date, format: :default
@@ -47,7 +47,7 @@
%td.text-right= hours_to_humanize leave_time.locked_hours
%td.text-right= hours_to_humanize leave_time.used_hours
%td.text-right= hours_to_humanize leave_time.usable_hours
- %td.text-right= l leave_time.effective_date, format: :long
- %td.text-right= l leave_time.expiration_date, format: :long
+ %td.text-right= l leave_time.effective_date, format: :default
+ %td.text-right= l leave_time.expiration_date, format: :default
diff --git a/app/views/devise/mailer/confirmation_instructions.text.erb b/app/views/devise/mailer/confirmation_instructions.text.erb
new file mode 100644
index 00000000..e349c8ab
--- /dev/null
+++ b/app/views/devise/mailer/confirmation_instructions.text.erb
@@ -0,0 +1,5 @@
+Welcome <%= @email %>!
+
+You can confirm your account email through the link below:
+
+<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>
\ No newline at end of file
diff --git a/app/views/devise/mailer/password_change.text.erb b/app/views/devise/mailer/password_change.text.erb
new file mode 100644
index 00000000..4f9f9620
--- /dev/null
+++ b/app/views/devise/mailer/password_change.text.erb
@@ -0,0 +1,3 @@
+Hello <%= @resource.email %>!
+
+We're contacting you to notify you that your password has been changed.
diff --git a/app/views/devise/mailer/reset_password_instructions.text.erb b/app/views/devise/mailer/reset_password_instructions.text.erb
new file mode 100644
index 00000000..a307afa8
--- /dev/null
+++ b/app/views/devise/mailer/reset_password_instructions.text.erb
@@ -0,0 +1,8 @@
+Hello <%= @resource.email %>!
+
+Someone has requested a link to change your password. You can do this through the link below.
+
+<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>
+
+If you didn't request this, please ignore this email.
+Your password won't change until you access the link above and create a new one.
\ No newline at end of file
diff --git a/app/views/devise/mailer/unlock_instructions.text.erb b/app/views/devise/mailer/unlock_instructions.text.erb
new file mode 100644
index 00000000..e3ed33d0
--- /dev/null
+++ b/app/views/devise/mailer/unlock_instructions.text.erb
@@ -0,0 +1,7 @@
+Hello <%= @resource.email %>!
+
+Your account has been locked due to an excessive number of unsuccessful sign in attempts.
+
+Click the link below to unlock your account:
+
+<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>
diff --git a/app/views/leave_applications/_form.html.haml b/app/views/leave_applications/_form.html.haml
index 937c77d1..f8589924 100644
--- a/app/views/leave_applications/_form.html.haml
+++ b/app/views/leave_applications/_form.html.haml
@@ -1,14 +1,13 @@
%h2= t("captions.leave_applications.#{action_name}")
= simple_form_for current_object, url: url_for(action: action), method: method do |f|
- = f.error :base, error: sanitize(f.object.errors[:base].join('
'), tags: %w(a br), attributes: %w(href target))
- - if action_name == "edit"
- = f.input :leave_type, required: true, collection: LeaveApplication.enum_attributes_for_select(:leave_types), disabled: true
+ = f.error :base, error: sanitize(f.object.errors[:base].join('
'), tags: %w(a br), attributes: %w(href target))
+ - if action_name == 'edit'
+ = f.input :leave_type, required: true, collection: LeaveApplication.enum_attributes_for_select(:leave_types, except = [:remote]), disabled: true
- else
- = f.input :leave_type, require: true, collection: LeaveApplication.enum_attributes_for_select(:leave_types, except: [:remote])
- = f.input :start_time, date_time_picker_hash(:start, current_object[:start_time])
- = f.input :end_time, date_time_picker_hash(:end, current_object[:end_time])
+ = f.input :leave_type, required: true, collection: leave_type_dropdown_menu(action_name, current_user)
+ = f.input :start_time, as: :string, required: true, input_html: { data: { input: 'datetimepicker', format: 'Y/m/d H:i' } }
+ = f.input :end_time, as: :string, required: true, input_html: { data: { input: 'datetimepicker', format: 'Y/m/d H:i' } }
= f.error :hours, error: sanitize(f.object.errors[:hours].join('
'), tags: %w(br))
= f.input :description, required: true
- = f.button :submit, class: "submit"
-
+ = f.button :submit, class: "submit"
\ No newline at end of file
diff --git a/app/views/leave_applications/index.html.haml b/app/views/leave_applications/index.html.haml
index 424b11d6..29d0747f 100644
--- a/app/views/leave_applications/index.html.haml
+++ b/app/views/leave_applications/index.html.haml
@@ -1,4 +1,4 @@
-%h2= t("captions.leave_applications.index", year: specific_year)
+%h2= t("captions.leave_applications.index")
.panel.panel-default
.panel-heading= t('panel_header.filter_conditions')
@@ -10,9 +10,9 @@
= f.input :leave_type_eq, collection: LeaveApplication.enum_attributes_for_select(:leave_types),
include_blank: t('.plz_select_leave_type'), required: false, wrapper_html: { class: 'col-md-6' }
= f.input :end_date_gteq, wrapper_html: { class: 'date-input col-md-6' },
- input_html: { data: { input: 'datepicker', format: 'YYYY/MM/DD' } }, required: false
+ input_html: { data: { input: 'datepicker', format: 'Y/m/d' } }, required: false
= f.input :start_date_lteq, wrapper_html: { class: 'date-input col-md-6' },
- input_html: { data: { input: 'datepicker', format: 'YYYY/MM/DD' } }, required: false
+ input_html: { data: { input: 'datepicker', format: 'Y/m/d' } }, required: false
.text-right
= f.button :submit, class: 'btn-warning'
@@ -46,11 +46,11 @@
= link_to t("title.leave_applications.show"),
leave_application_path(leave),
class: "btn btn-primary"
- - if leave.may_revise?
+ - if leave.may_revise? and !leave.happened?
= link_to t("title.leave_applications.edit"),
edit_leave_application_path(leave),
class: "btn btn-warning"
- - if leave.may_cancel?
+ - if leave.may_cancel? and !leave.happened?
= link_to t("title.leave_applications.cancel"),
cancel_leave_application_path(leave),
class: "btn btn-danger",
@@ -62,4 +62,3 @@
.paginate
= paginate current_collection
-
\ No newline at end of file
diff --git a/app/views/leave_applications/show.html.haml b/app/views/leave_applications/show.html.haml
index 7c0439af..d0c7bc8d 100644
--- a/app/views/leave_applications/show.html.haml
+++ b/app/views/leave_applications/show.html.haml
@@ -44,26 +44,29 @@
%th= t_attribute(:updated_at, current_object)
%td= l current_object.updated_at, format: :long
-
-
-.panel.panel-info
- .panel-heading
- %h4= t_attribute(:leave_time_usages, current_object)
- %table.table
- %thead
- %tr
- %th.text-right #
- %th.text-center= t_attribute(:leave_type, LeaveTime)
- %th.text-right 使用時數
- %th.text-right= t_attribute(:quota,LeaveTime)
- %th.text-right= t_attribute(:effective_date,LeaveTime)
- %th.text-right= t_attribute(:expiration_date,LeaveTime)
- %tbody
- - current_object.leave_time_usages.each do |usage|
+- unless current_user.contractor?
+ .panel.panel-info
+ .panel-heading
+ %h4= t_attribute(:leave_time_usages, current_object)
+ %table.table
+ %thead
%tr
- %td.text-right= link_to usage.leave_time_id, leave_time_path(usage.leave_time_id)
- %td.text-center= LeaveTime.human_enum_value(:leave_type, usage.leave_time.leave_type)
- %td.text-right= hours_to_humanize usage.used_hours
- %td.text-right= hours_to_humanize usage.leave_time.usable_hours
- %td.text-right= l usage.leave_time.effective_date, format: :long
- %td.text-right= l usage.leave_time.expiration_date, format: :long
+ %th.text-right #
+ %th.text-center= t_attribute(:leave_type, LeaveTime)
+ %th.text-right 日期
+ %th.text-right 使用時數
+ %th.text-right= t_attribute(:quota,LeaveTime)
+ %th.text-right= t_attribute(:effective_date,LeaveTime)
+ %th.text-right= t_attribute(:expiration_date,LeaveTime)
+ %tbody
+ - current_object.leave_time_usages.each do |usage|
+ %tr
+ - if current_object.leave_type == 'sick'
+ %td.text-right= usage.leave_time_id
+ - else
+ %td.text-right= link_to usage.leave_time_id, leave_time_path(usage.leave_time_id)
+ %td.text-center= LeaveTime.human_enum_value(:leave_type, usage.leave_time.leave_type)
+ %td.text-right= usage.date
+ %td.text-right= hours_to_humanize usage.used_hours
+ %td.text-right= hours_to_humanize usage.leave_time.usable_hours
+ %td.text-right= l usage.leave_time.effective_date, format: :long
\ No newline at end of file
diff --git a/app/views/leave_times/index.html.haml b/app/views/leave_times/index.html.haml
index eedce259..bc69e9c1 100644
--- a/app/views/leave_times/index.html.haml
+++ b/app/views/leave_times/index.html.haml
@@ -6,7 +6,7 @@
.panel-body
= simple_form_for @q, url: url_for(action: :index), method: :get do |f|
= f.hidden_field :s, value: params.dig(:q, :s)
- = f.input :leave_type_eq, collection: LeaveTime.enum_attributes_for_select(:leave_types, [:fullpaid_sick, :halfpaid_sick]),
+ = f.input :leave_type_eq, collection: LeaveTime.enum_attributes_for_select(:leave_types),
include_blank: t('.plz_select_leave_type'), required: false,
wrapper_html: { class: 'col-md-6' }
= f.input :effective_true, collection: [[I18n.t('activerecord.attributes.leave_time.state.effective'), true], [I18n.t('activerecord.attributes.leave_time.state.expired'), false]],
@@ -36,7 +36,6 @@
= sort_link(@q, :expiration_date)
%tbody
- current_collection.each do |quota|
- - next if quota.leave_type == "fullpaid_sick" or quota.leave_type == "halfpaid_sick"
%tr
%td.text-right= link_to quota.id, leave_time_path(quota.id)
%td.text-center= LeaveTime.human_enum_value(:leave_type, quota.leave_type)
@@ -56,5 +55,3 @@
.text-center
= paginate current_collection
-
-
diff --git a/app/views/leave_times/show.html.haml b/app/views/leave_times/show.html.haml
index 302e4795..25bebdec 100644
--- a/app/views/leave_times/show.html.haml
+++ b/app/views/leave_times/show.html.haml
@@ -43,18 +43,18 @@
%th.text-right= t_attribute :start_time, LeaveApplication
%th.text-right= t_attribute :end_time, LeaveApplication
%tbody
- - current_object.leave_time_usages.each do |usage|
+ - current_object.leave_time_usages.group_by(&:leave_application).each do |usage|
%tr
%td.text-right
- = link_to usage.leave_application_id, leave_application_path(usage.leave_application_id)
- %td.text-center= LeaveApplication.human_enum_value(:leave_type, usage.leave_application.leave_type)
- %td.text-right= usage.leave_application.pending? ? hours_to_humanize(usage.used_hours) : '-'
- %td.text-right= usage.leave_application.approved? ? hours_to_humanize(usage.used_hours) : '-'
- %td.text-right= hours_to_humanize usage.leave_application.hours
+ = link_to usage[0].id, verify_backend_leave_application_path(usage[0])
+ %td.text-center= LeaveApplication.human_enum_value(:leave_type, usage[0].leave_type)
+ %td.text-right= usage[0].pending? ? hours_to_humanize(usage[1].sum(&:used_hours)) : '-'
+ %td.text-right= usage[0].approved? ? hours_to_humanize(usage[1].sum(&:used_hours)) : '-'
+ %td.text-right= hours_to_humanize usage[0].hours
%td.text-center
- - colored_state_label(usage.leave_application.status)
- %td.text-right= l usage.leave_application.start_time, format: :long
- %td.text-right= l usage.leave_application.end_time, format: :long
+ - colored_state_label(usage[0].status)
+ %td.text-right= l usage[0].start_time, format: :long
+ %td.text-right= l usage[0].end_time, format: :long
%tr
%th.active.text-right{colspan: 2}= t('.sum')
%td.text-right= hours_to_humanize current_object.leave_time_usages.select { |u| u.leave_application.pending? }.sum(&:used_hours)
diff --git a/app/views/mailers/information_mailer/cancel_application.html.haml b/app/views/mailers/information_mailer/cancel_application.html.haml
new file mode 100644
index 00000000..d9bc7dce
--- /dev/null
+++ b/app/views/mailers/information_mailer/cancel_application.html.haml
@@ -0,0 +1,7 @@
+%p Hello,
+%p
+ = @leave_application.user.name
+ just canceled a #{@leave_application.leave_type} leave application.
+%p
+ It's start_time is #{@leave_application.start_time} and end_time is #{@leave_application.end_time}.
+= link_to "Go check it. :)", "https://daikichi.5xruby.tw/backend/leave_applications/#{@leave_application.id}/verify"
\ No newline at end of file
diff --git a/app/views/mailers/information_mailer/cancel_application.text.erb b/app/views/mailers/information_mailer/cancel_application.text.erb
new file mode 100644
index 00000000..c9566f7b
--- /dev/null
+++ b/app/views/mailers/information_mailer/cancel_application.text.erb
@@ -0,0 +1,5 @@
+Hello,
+<%= @leave_application.user.name %> just canceled a <%= @leave_application.leave_type %> leave application.
+It's start_time is <%= @leave_application.start_time %> and end_time is <%= @leave_application.end_time%>.
+Go check it. :)
+https://daikichi.5xruby.tw/backend/leave_applications/<%= @leave_application.id%>/verify
\ No newline at end of file
diff --git a/app/views/mailers/information_mailer/new_application.html.haml b/app/views/mailers/information_mailer/new_application.html.haml
new file mode 100644
index 00000000..f6bafb44
--- /dev/null
+++ b/app/views/mailers/information_mailer/new_application.html.haml
@@ -0,0 +1,7 @@
+%p Hello,
+%p
+ = @leave_application.user.name
+ just applies a #{@leave_application.leave_type} leave application.
+%p
+ It's start_time is #{@leave_application.start_time} and end_time is #{@leave_application.end_time}.
+= link_to "Go check it. :)", "https://daikichi.5xruby.tw/backend/leave_applications/#{@leave_application.id}/verify"
diff --git a/app/views/mailers/information_mailer/new_application.text.erb b/app/views/mailers/information_mailer/new_application.text.erb
new file mode 100644
index 00000000..02e9bc31
--- /dev/null
+++ b/app/views/mailers/information_mailer/new_application.text.erb
@@ -0,0 +1,5 @@
+Hello,
+<%= @leave_application.user.name %> just applies a <%= @leave_application.leave_type %> leave application.
+It's start_time is <%= @leave_application.start_time %> and end_time is <%= @leave_application.end_time%>.
+Go check it. :)
+https://daikichi.5xruby.tw/backend/leave_applications/<%= @leave_application.id%>/verify
diff --git a/app/views/mailers/user_mailer/reply_leave_applicaiton_email.html.haml b/app/views/mailers/user_mailer/reply_leave_applicaiton_email.html.haml
new file mode 100644
index 00000000..9d2e357f
--- /dev/null
+++ b/app/views/mailers/user_mailer/reply_leave_applicaiton_email.html.haml
@@ -0,0 +1,5 @@
+%p
+ 嗨 #{@leave_application.user.name},
+%p
+ 你 #{l @leave_application.start_time, format: :long} 的 #{LeaveApplication.human_enum_value(:leave_type, @leave_application.leave_type)} 已經被 #{LeaveApplication.human_enum_value(:status, @leave_application.status)} 囉!
+= link_to "點此連結查看詳情", "https://daikichi.5xruby.tw/leave_applications/#{@leave_application.id}"
diff --git a/app/views/mailers/user_mailer/reply_leave_applicaiton_email.text.erb b/app/views/mailers/user_mailer/reply_leave_applicaiton_email.text.erb
new file mode 100644
index 00000000..db3126c4
--- /dev/null
+++ b/app/views/mailers/user_mailer/reply_leave_applicaiton_email.text.erb
@@ -0,0 +1,4 @@
+嗨 <%= @leave_application.user.name %>,
+你的 <%= l @leave_application.start_time, format: :long%> 的 <%= LeaveApplication.human_enum_value(:leave_type, @leave_application.leave_type) %> 已經被 <%= LeaveApplication.human_enum_value(:status, @leave_application.status) %> 囉!
+<%= link_to "點此連結查看詳情:)", "https://daikichi.5xruby.tw/leave_applications/#{@leave_application.id}" %>
+
diff --git a/app/views/pages/_alert_modal.html.haml b/app/views/pages/_alert_modal.html.haml
new file mode 100644
index 00000000..845a1a7d
--- /dev/null
+++ b/app/views/pages/_alert_modal.html.haml
@@ -0,0 +1,13 @@
+#page-alert-modal.modal{"aria-hidden" => "true", "aria-labelledby" => "mainModalLabel", :role => "dialog", :tabindex => "-1"}
+ .modal-dialog
+ .modal-content
+ .modal-header
+ %h3{:style => "display: inline-block;"} 注意
+ %button.close{"data-dismiss" => "modal", :type => "button"}
+ %span{"aria-hidden" => "true"} ×
+ %span.sr-only x
+ .modal-body
+ %p 申請 remote 或請假,麻煩主動通知 Sabrina 或老闆,以利審核進度。未審核代表未完成請假手續 ,敬請協助配合,謝謝。
+ .modal-footer
+ %button.btn{"aria-hidden" => "true", "data-dismiss" => "modal"} OK
+
diff --git a/app/views/pages/index.html.haml b/app/views/pages/index.html.haml
index e69de29b..e94ff4f9 100644
--- a/app/views/pages/index.html.haml
+++ b/app/views/pages/index.html.haml
@@ -0,0 +1,20 @@
+.panel.panel-info
+ .panel-heading 簡易操作說明
+ .panel-body
+ 1. 工時設定為每日 (9:30 - 12:30;12:30 - 18:30),且請假的最小單位為一小時,若早於 9:30 會視同 9:30 或晚於 18:30 會視同 18:30。
+ %br
+ 2. 若需請整天、多天連續假,都可以直接選取頭尾日期時間,系統會自動扣除非上班小時數。
+ %br
+ %br
+ %br
+ 備註:
+ %br
+ ☞ 若有任何問題請至
+ %a{href: 'https://github.com/5xRuby/daikichi/issues'}>_Github_
+ 開 issue,會盡快修復
+
+ %br
+ ☞ 關於請假規則有任何疑問請查看
+ %a{href: 'https://docs.google.com/document/d/1ei1AT3qlV87MV2Gbn-dij-66rGXDkctpQDruGE_mWMg/edit'}>_請假手冊_
+
+
diff --git a/app/views/remote/new.html.haml b/app/views/remote/new.html.haml
index 7b7a2471..9919cfad 100644
--- a/app/views/remote/new.html.haml
+++ b/app/views/remote/new.html.haml
@@ -1,12 +1,10 @@
-= content_for :additional_script, javascript_include_tag("pages/leave_applications")
-
%h2= t("captions.remote.#{action_name}")
= simple_form_for current_object, url: url_for(action: :create), method: :post, as: :remote_application do |f|
= f.error :base, error: sanitize(f.object.errors[:base].join('
'), tags: %w(a br), attributes: %w(href target))
= f.input :leave_type, disabled: true, label: "類型",
input_html: { value: I18n.t("activerecord.attributes.leave_application.leave_types.remote") }
- = f.input :start_time, date_time_picker_hash(:start, current_object[:start_time])
- = f.input :end_time, date_time_picker_hash(:end, current_object[:end_time])
+ = f.input :start_time, as: :string, input_html: { data: { input: 'datetimepicker', format: 'Y/m/d H:i' } }
+ = f.input :end_time, as: :string, input_html: { data: { input: 'datetimepicker', format: 'Y/m/d H:i' } }
= f.error :hours, error: sanitize(f.object.errors[:hours].join('
'), tags: %w(br))
= f.input :description, required: true
= f.button :submit, class: "submit"
diff --git a/app/views/shared/_leave_application_dropdown.html.haml b/app/views/shared/_leave_application_dropdown.html.haml
new file mode 100644
index 00000000..2c1a9737
--- /dev/null
+++ b/app/views/shared/_leave_application_dropdown.html.haml
@@ -0,0 +1,7 @@
+%li.dropdown
+ = dropdown_title t("nav.leave_applications")
+ %ul.dropdown-menu
+ %li= link_to t("title.leave_applications.new"), new_leave_application_path
+ %li= link_to t("title.leave_applications.new_remote"), new_remote_path
+ %li= link_to t("title.leave_times.index"), leave_times_path
+ %li= link_to t("title.leave_applications.index"), leave_applications_path
\ No newline at end of file
diff --git a/app/views/shared/_leave_applocation_dropdown_contractor.html.haml b/app/views/shared/_leave_applocation_dropdown_contractor.html.haml
new file mode 100644
index 00000000..2018675c
--- /dev/null
+++ b/app/views/shared/_leave_applocation_dropdown_contractor.html.haml
@@ -0,0 +1,5 @@
+%li.dropdown
+ = dropdown_title t("nav.leave_applications")
+ %ul.dropdown-menu
+ %li= link_to t("title.leave_applications.new"), new_leave_application_path
+ %li= link_to t("title.leave_applications.index"), leave_applications_path
\ No newline at end of file
diff --git a/app/views/shared/_navigation.html.haml b/app/views/shared/_navigation.html.haml
index 6d788dce..c6ec50ab 100644
--- a/app/views/shared/_navigation.html.haml
+++ b/app/views/shared/_navigation.html.haml
@@ -10,14 +10,10 @@
#nav-collapse.collapse.navbar-collapse
%ul.nav.navbar-nav
- - if can? :view, LeaveApplication
- %li.dropdown
- = dropdown_title t("nav.leave_applications")
- %ul.dropdown-menu
- %li= link_to t("title.leave_applications.new"), new_leave_application_path
- %li= link_to t("title.leave_applications.new_remote"), new_remote_path
- %li= link_to t("title.leave_times.index"), leave_times_path
- %li= link_to t("title.leave_applications.index"), leave_applications_path
+ - if (can? :view, LeaveApplication) && !current_user.try(:contractor?)
+ = render partial: 'shared/leave_application_dropdown'
+ - if current_user.try(:contractor?)
+ = render partial: 'shared/leave_applocation_dropdown_contractor'
- if can? :manage, User
%li.dropdown
@@ -31,10 +27,12 @@
= dropdown_title t("nav.manage")
%ul.dropdown-menu
%li= link_to t("title.backend/leave_times.new"), new_backend_leave_time_path
+ %li= link_to t("title.backend/leave_times.batch_append_quota"),batch_new_backend_leave_times_path
+ %li= link_to t("title.backend/leave_applications.new"), new_backend_leave_application_path
%li= link_to t("title.backend/leave_applications.index"),
backend_leave_applications_path(status: :pending)
%li= link_to t("captions.backend/leave_applications.statistics"),
- statistics_backend_leave_applications_path(year: specific_year, month: specific_month)
+ statistics_backend_leave_applications_path(year: specific_year, month: specific_month, role: "")
%li= link_to t("title.backend/leave_times.index"),
backend_leave_times_path
diff --git a/config/application.yml.sample b/config/application.yml.sample
index 1ce7dc8d..940c09fc 100644
--- a/config/application.yml.sample
+++ b/config/application.yml.sample
@@ -43,57 +43,65 @@ defaults: &defaults
rejected: rejected
canceled: canceled
leave_types:
- annual: annual
- bonus: bonus
- # unpaid: unpaid
- sick: sick
+ fullpaid_sick: fullpaid_sick
+ halfpaid_sick: halfpaid_sick
+ personal: personal
official: official
+ menstrual: menstrual # 生理假
+ occpational_sick: occpational_sick # 公傷病假
marriage: marriage
compassionate: compassionate
- personal: personal
+ maternity: maternity
remote: remote
+ paid_vacation: paid_vacation
available_quota_types:
- annual:
- - annual
- bonus:
- - bonus
- unpaid:
- - unpaid
- sick:
- - sick # Deprecated
+ fullpaid_sick:
- fullpaid_sick
+ halfpaid_sick:
- halfpaid_sick
+ personal:
+ - bonus
+ - annual
+ - personal
official:
- official
marriage:
- marriage
compassionate:
- compassionate
- # Deprecated
- personal:
- - bonus
- - annual
- - personal
+ maternity:
+ - maternity
remote:
- remote
+ # 生理假
+ menstrual:
+ - menstrual
+ # 公傷病假
+ occpational_sick:
+ - occpational_sick
+ # 旅遊假
+ paid_vacation:
+ - paid_vacation
leave_times:
quota_types:
- annual: annual
bonus: bonus
- unpaid: unpaid
- sick: sick # Deprecated
+ annual: annual
+ personal: personal #should be deprecated
fullpaid_sick: fullpaid_sick
halfpaid_sick: halfpaid_sick
+ remote: remote
official: official
marriage: marriage
compassionate: compassionate
- remote: remote
- personal: personal #should be deprecated
+ maternity: maternity
+ menstrual: menstrual # 生理假
+ occpational_sick: occpational_sick # 公傷病假
+ paid_vacation: paid_vacation
leed_days:
monthly: 5 # working.days
- join_date_based: 40 # days
+ join_date_based: 60 # days
leave_types:
annual:
@@ -139,8 +147,8 @@ defaults: &defaults
creation: join_date_based
quota: 23
remote:
- creation: monthly
- quota: 2 # days
+ creation: weekly
+ quota: 1 # days
marriage:
creation: manually
quota: 8 # days
@@ -154,6 +162,12 @@ defaults: &defaults
creation: none
bonus:
creation: none
+ menstrual:
+ creation: manually
+ quota: 1
+ effective: 2 # days
+ occpational_sick:
+ creation: none
backend:
default_leave_pool_type: bonus
@@ -170,3 +184,6 @@ test:
production:
<<: *defaults
+
+staging:
+ <<: *defaults
diff --git a/config/deploy.rb b/config/deploy.rb
index c9fc4596..f81d7179 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -30,11 +30,12 @@
set :pty, false
# Default value for :linked_files is []
-set :linked_files, %w{config/database.yml config/application.yml config/secrets.yml}
+set :linked_files, %w{config/database.yml config/application.yml config/secrets.yml config/fluent-logger.yml}
# Default value for linked_dirs is []
-# set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
+set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
+
# Default value for default_env is {}
set :default_env, { path: "$PATH:/usr/local/ruby23/bin:/usr/local/ruby-2.4.1/bin:" }
diff --git a/config/deploy/production.rb b/config/deploy/production.rb
index 9510baf3..08cb0d48 100644
--- a/config/deploy/production.rb
+++ b/config/deploy/production.rb
@@ -1,4 +1,4 @@
set :deploy_to, '/home/deploy/daikichi.5xruby.tw'
-role :app, %w{deploy@10.128.128.154}
-role :web, %w{deploy@10.128.128.154}
-role :db, %w{deploy@10.128.128.154}
\ No newline at end of file
+role :app, %w{deploy@do.5xruby.tw}
+role :web, %w{deploy@do.5xruby.tw}
+role :db, %w{deploy@do.5xruby.tw}
\ No newline at end of file
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 8ec4ca90..869adbbd 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -48,5 +48,17 @@
# Use an evented file watcher to asynchronously detect changes in source code,
# routes, locales, etc. This feature depends on the listen gem.
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
+ config.action_mailer.show_previews = true
+ config.action_mailer.preview_path = "#{Rails.root}/app/mailers/previews"
config.action_mailer.delivery_method = :letter_opener
+ # config.action_mailer.delivery_method = :smtp
+ # config.action_mailer.smtp_settings = {
+ # user_name: Settings.smtp.username,
+ # password: Settings.smtp.password,
+ # domain: Settings.smtp.domain,
+ # address: Settings.smtp.address,
+ # port: Settings.smtp.port,
+ # authentication: Settings.smtp.authentication,
+ # enable_starttls_auto: Settings.smtp.enable_starttls_auto
+ # }
end
diff --git a/config/environments/production.rb b/config/environments/production.rb
index e6167eef..0aea947d 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -96,4 +96,8 @@
authentication: Settings.smtp.authentication,
enable_starttls_auto: Settings.smtp.enable_starttls_auto
}
+
+ #config.logger = ActFluentLoggerRails::Logger.new
+ #config.lograge.enabled = true
+ #config.lograge.formatter = Lograge::Formatters::Logstash.new
end
diff --git a/config/fluent-logger.yml.example b/config/fluent-logger.yml.example
new file mode 100644
index 00000000..bd13c260
--- /dev/null
+++ b/config/fluent-logger.yml.example
@@ -0,0 +1,17 @@
+development:
+ fluent_host: '127.0.0.1'
+ fluent_port: 24224
+ tag: '5xruby.daikichi'
+ messages_type: 'string'
+
+test:
+ fluent_host: '127.0.0.1'
+ fluent_port: 24224
+ tag: '5xruby.daikichi'
+ messages_type: 'string'
+
+production:
+ fluent_host: '127.0.0.1'
+ fluent_port: 24224
+ tag: '5xruby.daikichi'
+ messages_type: 'string'
diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb
index 533511f9..e756fba5 100644
--- a/config/initializers/assets.rb
+++ b/config/initializers/assets.rb
@@ -10,3 +10,4 @@
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
# Rails.application.config.assets.precompile += %w( search.js )
Rails.application.config.assets.precompile += [ "pages/*" ]
+Rails.application.config.assets.precompile += %w( page_alert.js )
diff --git a/config/initializers/biz.rb b/config/initializers/biz.rb
index 6f1b653d..73470c70 100644
--- a/config/initializers/biz.rb
+++ b/config/initializers/biz.rb
@@ -61,6 +61,7 @@ class Config
Date.new(2017, 7, 22), # 週六休假
Date.new(2017, 7, 29), # 週六休假
Date.new(2017, 8, 5), # 週六休假
+ Date.new(2017, 8, 12), # 週六休假
Date.new(2017, 8, 19), # 週六休假
Date.new(2017, 8, 26), # 週六休假
Date.new(2017, 9, 2), # 週六休假
@@ -80,7 +81,75 @@ class Config
Date.new(2017, 12, 9), # 週六休假
Date.new(2017, 12, 16), # 週六休假
Date.new(2017, 12, 23), # 週六休假
- Date.new(2017, 12, 30) # 週六休假
+ Date.new(2017, 12, 30), # 週六休假
+
+ # 2018 休假日設定
+ Date.new(2018, 1, 1),
+ Date.new(2018, 2, 15), # 除夕放假
+ Date.new(2018, 2, 16), # 春節
+ Date.new(2018, 2, 19), # 春節放三天逢週六、週日補假二天
+ Date.new(2018, 2, 20), # 春節放三天逢週六、週日補假二天
+ Date.new(2018, 2, 28), # 和平紀念日
+ Date.new(2018, 4, 4), # 兒童節、清明節連假
+ Date.new(2018, 4, 5), # 兒童節、清明節連假
+ Date.new(2018, 4, 6), # 兒童節、清明節連假
+ Date.new(2018, 5, 1), # 五一勞動節
+ Date.new(2018, 6, 18), # 端午節
+ Date.new(2018, 9, 24), # 中秋節放假
+ Date.new(2018, 10, 10), # 國慶日放假
+ Date.new(2018, 12, 31), # 元旦逢週二,彈性調整放假
+
+ # 週六放假設定
+ Date.new(2018, 1, 6), # 週六休假
+ Date.new(2018, 1, 13), # 週六休假
+ Date.new(2018, 1, 20), # 週六休假
+ Date.new(2018, 1, 27), # 週六休假
+ Date.new(2018, 2, 3), # 週六休假
+ Date.new(2018, 2, 10), # 週六休假
+ Date.new(2018, 2, 17), # 週六休假
+ Date.new(2018, 2, 24), # 週六休假
+ Date.new(2018, 3, 3), # 週六休假
+ Date.new(2018, 3, 10), # 週六休假
+ Date.new(2018, 3, 17), # 週六休假
+ Date.new(2018, 3, 24), # 週六休假
+ Date.new(2018, 4, 7), # 週六休假
+ Date.new(2018, 4, 14), # 週六休假
+ Date.new(2018, 4, 21), # 週六休假
+ Date.new(2018, 4, 28), # 週六休假
+ Date.new(2018, 5, 5), # 週六休假
+ Date.new(2018, 5, 12), # 週六休假
+ Date.new(2018, 5, 19), # 週六休假
+ Date.new(2018, 5, 26), # 週六休假
+ Date.new(2018, 6, 2), # 週六休假
+ Date.new(2018, 6, 9), # 週六休假
+ Date.new(2018, 6, 16), # 週六休假
+ Date.new(2018, 6, 23), # 週六休假
+ Date.new(2018, 6, 30), # 週六休假
+ Date.new(2018, 7, 7), # 週六休假
+ Date.new(2018, 7, 14), # 週六休假
+ Date.new(2018, 7, 21), # 週六休假
+ Date.new(2018, 7, 28), # 週六休假
+ Date.new(2018, 8, 4), # 週六休假
+ Date.new(2018, 8, 11), # 週六休假
+ Date.new(2018, 8, 18), # 週六休假
+ Date.new(2018, 8, 25), # 週六休假
+ Date.new(2018, 9, 1), # 週六休假
+ Date.new(2018, 9, 8), # 週六休假
+ Date.new(2018, 9, 15), # 週六休假
+ Date.new(2018, 9, 22), # 週六休假
+ Date.new(2018, 9, 29), # 週六休假
+ Date.new(2018, 10, 6), # 週六休假
+ Date.new(2018, 10, 13), # 週六休假
+ Date.new(2018, 10, 20), # 週六休假
+ Date.new(2018, 10, 27), # 週六休假
+ Date.new(2018, 11, 3), # 週六休假
+ Date.new(2018, 11, 10), # 週六休假
+ Date.new(2018, 11, 17), # 週六休假
+ Date.new(2018, 11, 24), # 週六休假
+ Date.new(2018, 12, 1), # 週六休假
+ Date.new(2018, 12, 8), # 週六休假
+ Date.new(2018, 12, 15), # 週六休假
+ Date.new(2018, 12, 29) # 週六休假
]
config.time_zone = 'Asia/Taipei'
diff --git a/config/locales/meta_data.zh_TW.yml b/config/locales/meta_data.zh_TW.yml
index 322b17ab..86fa4d95 100644
--- a/config/locales/meta_data.zh_TW.yml
+++ b/config/locales/meta_data.zh_TW.yml
@@ -38,7 +38,9 @@ zh-TW:
bonus: '補休'
compassionate: '喪假'
sick: '病假'
- unpaid: '無薪事假'
+ menstrual: '生理假'
+ occpational_sick: '公傷病假'
+ paid_vacation: '旅遊假'
user: "員工"
name: "擁有者"
leave_type: "假別"
@@ -70,13 +72,17 @@ zh-TW:
leave_types:
annual: '特別休假'
bonus: '補充休假'
- sick: '病假'
- personal: '無薪事假'
+ fullpaid_sick: '全薪病假'
+ halfpaid_sick: '半薪病假'
+ personal: '事假'
remote: '遠端工作'
official: '公假'
marriage: '婚假'
compassionate: '喪假'
maternity: '產假'
+ menstrual: '生理假'
+ occpational_sick: '公傷病假'
+ paid_vacation: '旅遊假'
user: "員工"
start_time: "開始時間"
end_time: "結束時間"
@@ -151,6 +157,7 @@ zh-TW:
edit: "編輯"
destroy: "刪除"
backend/leave_applications:
+ new: "新增員工假單"
index: "審核假單"
show: "檢視"
verify: "審核"
@@ -161,6 +168,7 @@ zh-TW:
backend/leave_times:
index: "員工休假額度"
new: "新增員工休假額度"
+ batch_append_quota: "批次新增員工休假額度"
edit: "修改"
delete: "刪除"
change_type: "切換休假種類至"
@@ -190,7 +198,7 @@ zh-TW:
leave_times:
index: "請假額度"
leave_applications:
- index: "%{year} 年 所有假單"
+ index: "歷年假單"
show: "%{start_day} - %{end_day} %{type}假單"
new: "新增假單"
create: "新增假單"
@@ -206,12 +214,17 @@ zh-TW:
create: "新增員工"
edit: "修正員工資料"
backend/leave_applications:
+ new: "新增員工假單"
+ create: "新增員工假單"
+ new/hint: "提醒:管理員主動新增之假單狀態會直接是核准。"
+ create/hint: "提醒:管理員主動新增之假單狀態會直接是核准。"
index: "審核假單"
verify: "審核假單"
statistics: "員工休假統計"
backend/leave_times:
index: "員工休假額度"
new: "新增員工休假額度"
+ batch_new: "批次新增員工休假額度"
append_quota: "新增員工休假額度"
edit: "修改員工休假"
tools: "工具"
@@ -222,6 +235,7 @@ zh-TW:
destroy: "刪除成功"
revise: "已修改假單"
cancel: "已取消假單"
+ batch_create: '批次新增員工休假額度成功'
warnings:
self_manage: "申請人不得自行審核"
diff --git a/config/locales/simple_form.zh_TW.yml b/config/locales/simple_form.zh_TW.yml
index d1f0195c..cdabde7b 100644
--- a/config/locales/simple_form.zh_TW.yml
+++ b/config/locales/simple_form.zh_TW.yml
@@ -23,6 +23,7 @@ zh-TW:
maternity: '產假'
compassionate: '喪假'
absent: '曠職'
+ paid_vacation: '旅遊假'
labels:
q:
leave_type_eq: 依額度類別篩選
diff --git a/config/locales/zh_TW.yml b/config/locales/zh_TW.yml
index fa264623..4a2c7007 100644
--- a/config/locales/zh_TW.yml
+++ b/config/locales/zh_TW.yml
@@ -2,13 +2,13 @@
zh-TW:
date:
abbr_day_names:
- - 周日
- - 周一
- - 周二
- - 周三
- - 周四
- - 周五
- - 周六
+ - 週日
+ - 週一
+ - 週二
+ - 週三
+ - 週四
+ - 週五
+ - 週六
abbr_month_names:
-
- 1月
@@ -35,7 +35,7 @@ zh-TW:
default: "%Y-%m-%d"
long: "%Y年%b%d日"
short: "%b%d日"
- detailed: "%Y年 %m月 %d日 (%a)"
+ detailed: "%Y-%m-%d (%a)"
month_names:
-
- 1月
@@ -200,7 +200,8 @@ zh-TW:
am: 上午
formats:
default: "%Y年%b%d日 %A %H:%M:%S %Z"
- long: "%Y年 %m月 %d日 (%a) %H:%M"
+ long: "%Y-%m-%d (%a) %H:%M"
short: "%b%d日 %H:%M"
pm: 下午
humanize_working_hour: "%{days} 天 %{hours} 小時 (%{total}小時)"
+ total_hour: "%{total} 小時"
diff --git a/config/routes.rb b/config/routes.rb
index 74010c8a..3ca954ec 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -7,13 +7,15 @@
namespace :backend do
resources :users
- resources :leave_applications, only: [:index, :update] do
+ resources :leave_applications, except: [:show, :destroy] do
get :verify, on: :member
get :statistics, on: :collection
end
resources :leave_times, except: [:edit, :update, :destroy] do
post :append_quota, on: :collection
+ get :batch_new, on: :collection
+ post :batch_create, on: :collection
end
resources :bonus_leave_time_logs, only: [:index, :update]
diff --git a/config/schedule.rb b/config/schedule.rb
index 81dedd0f..512d7292 100644
--- a/config/schedule.rb
+++ b/config/schedule.rb
@@ -1,9 +1,4 @@
-# 每年 10/1 00:05 初始化隔年休假額度
-every '5 0 1 10 *' do
- rake "leave_time:init[Time.current.year + 1,'force']"
-end
-
-# 每日 00:10 檢查 fulltime employee 是否獲得 8hr 特休
-every "10 0 * * *" do
- rake "leave_time:refill"
+# 每日 00:00 檢查是否初始化額度(Monthly and Join_date_base)
+every "0 0 * * *" do
+ rake "import:import"
end
diff --git a/db/migrate/20170616091946_delete_column_of_leave_application.rb b/db/migrate/20170616091946_delete_column_of_leave_application.rb
index b71395bb..2c286d28 100644
--- a/db/migrate/20170616091946_delete_column_of_leave_application.rb
+++ b/db/migrate/20170616091946_delete_column_of_leave_application.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
class DeleteColumnOfLeaveApplication < ActiveRecord::Migration[5.0]
def change
- remove_column :leave_applications, :uuid
+ remove_column :leave_applications, :uuid
end
end
diff --git a/db/migrate/20170620024946_delete_leave_application_logs.rb b/db/migrate/20170620024946_delete_leave_application_logs.rb
index de84942e..014da3f4 100644
--- a/db/migrate/20170620024946_delete_leave_application_logs.rb
+++ b/db/migrate/20170620024946_delete_leave_application_logs.rb
@@ -7,7 +7,7 @@ def change
t.integer :amount, default: 0
t.boolean :returning?, default: false
- t.timestamps
+ t.timestamps
end
end
end
diff --git a/db/migrate/20170629025755_create_crono_jobs.rb b/db/migrate/20170629025755_create_crono_jobs.rb
index 60706fa5..a98cb66f 100644
--- a/db/migrate/20170629025755_create_crono_jobs.rb
+++ b/db/migrate/20170629025755_create_crono_jobs.rb
@@ -2,7 +2,7 @@ class CreateCronoJobs < ActiveRecord::Migration
def self.up
create_table :crono_jobs do |t|
t.string :job_id, null: false
- t.text :log, limit: 1073741823 # LONGTEXT for MySQL
+ t.text :log, limit: 1_073_741_823 # LONGTEXT for MySQL
t.datetime :last_performed_at
t.boolean :healthy
t.timestamps null: false
diff --git a/db/migrate/20170810032132_update_leave_application_leave_type.rb b/db/migrate/20170810032132_update_leave_application_leave_type.rb
new file mode 100644
index 00000000..d622cdb2
--- /dev/null
+++ b/db/migrate/20170810032132_update_leave_application_leave_type.rb
@@ -0,0 +1,10 @@
+class UpdateLeaveApplicationLeaveType < ActiveRecord::Migration[5.0]
+ def self.up
+ LeaveApplication.where(leave_type: [:annual, :bonus]).each do |q|
+ q.update!(leave_type: :personal)
+ end
+ end
+
+ def self.down
+ end
+end
diff --git a/db/migrate/20171229103357_add_date_to_leave_time_usages.rb b/db/migrate/20171229103357_add_date_to_leave_time_usages.rb
new file mode 100644
index 00000000..a49f844e
--- /dev/null
+++ b/db/migrate/20171229103357_add_date_to_leave_time_usages.rb
@@ -0,0 +1,5 @@
+class AddDateToLeaveTimeUsages < ActiveRecord::Migration[5.0]
+ def change
+ add_column :leave_time_usages, :date, :date
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 9454d1fc..62ee4cba 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20170629025755) do
+ActiveRecord::Schema.define(version: 20171229103357) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -68,6 +68,7 @@
t.integer "used_hours"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.date "date"
t.index ["leave_application_id"], name: "index_leave_time_usages_on_leave_application_id", using: :btree
t.index ["leave_time_id"], name: "index_leave_time_usages_on_leave_time_id", using: :btree
end
diff --git a/lib/tasks/create_new_format_usages.rake b/lib/tasks/create_new_format_usages.rake
new file mode 100644
index 00000000..4ea432a4
--- /dev/null
+++ b/lib/tasks/create_new_format_usages.rake
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+namespace :generate_usages do
+ desc "Generate leave time usage in new format for approved applications"
+ task approved: :environment do
+ LeaveApplication.approved.find_each do |la|
+ la.leave_time_usages.each do |usage|
+ usage.leave_time.unuse_hours!(usage.used_hours)
+ usage.destroy
+ end
+ raise ActiveRecord::Rollback if !LeaveTimeUsageBuilder.new(la).build_leave_time_usages and !la.special_type?
+ end
+
+ LeaveApplication.approved.find_each do |la|
+ la.leave_time_usages.group_by(&:leave_time_id).each do |usages|
+ leave_time = LeaveTime.find(usages[0])
+ leave_time.use_hours!(usages[1].sum(&:used_hours))
+ end
+ end
+ end
+
+ desc "Generate leave time usage in new format for pending leave applications"
+ task pending: :environment do
+ LeaveApplication.pending.find_each do |la|
+ la.leave_time_usages.each do |usage|
+ usage.leave_time.unlock_hours!(usage.used_hours)
+ usage.destroy
+ end
+ raise ActiveRecord::Rollback if !LeaveTimeUsageBuilder.new(la).build_leave_time_usages and !la.special_type?
+ end
+ end
+end
diff --git a/lib/tasks/import_data.rake b/lib/tasks/import_data.rake
index ca390b2e..a505f97a 100644
--- a/lib/tasks/import_data.rake
+++ b/lib/tasks/import_data.rake
@@ -8,6 +8,7 @@ namespace :import_data do
user.email = Settings.admin_user.email
user.name = Settings.admin_user.name
user.role = Settings.admin_user.role
+ user.join_date = Date.current
user.password = Settings.admin_user.password
user.password_confirmation = Settings.admin_user.password
end
diff --git a/spec/controllers/backend/leave_times_controller_spec.rb b/spec/controllers/backend/leave_times_controller_spec.rb
index d6f70bd1..761b0bde 100644
--- a/spec/controllers/backend/leave_times_controller_spec.rb
+++ b/spec/controllers/backend/leave_times_controller_spec.rb
@@ -1,4 +1,15 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Backend::LeaveTimesController, type: :controller do
+ describe 'POST #batch_create' do
+ before do
+ sign_in create(:manager_eddie)
+ 5.times { FactoryGirl.create(:user) }
+ end
+ it 'add leave time to each users' do
+ expect do
+ post :batch_create, params: { leave_time: { 'user_id' => User.select(:id).last(4), 'leave_type' => 'personal', 'quota' => '3', 'effective_date' => '2017/12/15', 'expiration_date' => '2017/12/25', 'remark' => 'fd' } }
+ end.to change(LeaveTime, :count).by(4)
+ end
+ end
end
diff --git a/spec/controllers/remote_controller_spec.rb b/spec/controllers/remote_controller_spec.rb
index 4345a68c..5420bdd0 100644
--- a/spec/controllers/remote_controller_spec.rb
+++ b/spec/controllers/remote_controller_spec.rb
@@ -1,5 +1,4 @@
require 'rails_helper'
RSpec.describe RemoteController, type: :controller do
-
end
diff --git a/spec/factories/leave_applicaiton.rb b/spec/factories/leave_applicaiton.rb
index 46bd5946..fbcf26da 100644
--- a/spec/factories/leave_applicaiton.rb
+++ b/spec/factories/leave_applicaiton.rb
@@ -7,8 +7,12 @@
start_time { Daikichi::Config::Biz.periods.after(Time.current.beginning_of_day).first.start_time }
end_time { Daikichi::Config::Biz.periods.after(Time.current.beginning_of_day).first(2).second.end_time }
- trait :sick do
- leave_type 'sick'
+ trait :halfpaid_sick do
+ leave_type 'halfpaid_sick'
+ end
+
+ trait :fullpaid_sick do
+ leave_type 'fullpaid_sick'
end
trait :personal do
diff --git a/spec/features/leave_application/create_leave_application.rb b/spec/features/leave_application/create_leave_application.rb
new file mode 100644
index 00000000..bab42211
--- /dev/null
+++ b/spec/features/leave_application/create_leave_application.rb
@@ -0,0 +1,128 @@
+require 'rails_helper'
+
+feature "special type leave application" do
+ context "created" do
+ let!(:user) { FactoryGirl.create(:user, :fulltime, join_date: Date.current - 1.year - 1.day) }
+
+ before :each do
+ visit '/users/sign_in'
+ login user.login_name, user.password
+ end
+
+ scenario "menstrual" do
+ visit '/leave_applications/new'
+ within("form#new_leave_application") do
+ select('生理假', from: 'leave_application_leave_type')
+ find('[id^="leave_application_start_time"]').set("2018/02/12 09:30")
+ find('[id^="leave_application_start_time"]').set("2018/02/12 18:30")
+ fill_in('事由', with: 'menstrual')
+ end
+ click_button '送出'
+ expect(page).to have_content '生理假'
+ end
+
+ scenario "occpational_sick" do
+ visit '/leave_applications/new'
+ within("form#new_leave_application") do
+ select('公傷病假', from: 'leave_application_leave_type')
+ find('[id^="leave_application_start_time"]').set("2018/02/12 09:30")
+ find('[id^="leave_application_start_time"]').set("2018/02/12 18:30")
+ fill_in('事由', with: 'occpational_sick')
+ end
+ click_button '送出'
+ expect(page).to have_content '公傷病假'
+ end
+
+ scenario "official" do
+ visit '/leave_applications/new'
+ within("form#new_leave_application") do
+ select('公假', from: 'leave_application_leave_type')
+ find('[id^="leave_application_start_time"]').set("2018/02/12 09:30")
+ find('[id^="leave_application_start_time"]').set("2018/02/12 18:30")
+ fill_in('事由', with: 'official')
+ end
+ click_button '送出'
+ expect(page).to have_content '公假'
+ end
+
+ scenario "compassionate" do
+ visit '/leave_applications/new'
+ within("form#new_leave_application") do
+ select('喪假', from: 'leave_application_leave_type')
+ find('[id^="leave_application_start_time"]').set("2018/02/12 09:30")
+ find('[id^="leave_application_start_time"]').set("2018/02/12 18:30")
+ fill_in('事由', with: 'compassionate')
+ end
+ click_button '送出'
+ expect(page).to have_content '喪假'
+ end
+
+ scenario "marriage" do
+ visit '/leave_applications/new'
+ within("form#new_leave_application") do
+ select('婚假', from: 'leave_application_leave_type')
+ find('[id^="leave_application_start_time"]').set("2018/02/12 09:30")
+ find('[id^="leave_application_start_time"]').set("2018/02/12 18:30")
+ fill_in('事由', with: 'marriage')
+ end
+ click_button '送出'
+ expect(page).to have_content '婚假'
+ end
+
+ scenario "maternity" do
+ visit '/leave_applications/new'
+ within("form#new_leave_application") do
+ select('產假', from: 'leave_application_leave_type')
+ find('[id^="leave_application_start_time"]').set("2018/02/12 09:30")
+ find('[id^="leave_application_start_time"]').set("2018/02/12 18:30")
+ fill_in('事由', with: 'maternity')
+ end
+ click_button '送出'
+ expect(page).to have_content '產假'
+ end
+
+ scenario "paid_vacation" do
+ visit '/leave_applications/new'
+ within("form#new_leave_application") do
+ select('旅遊假', from: 'leave_application_leave_type')
+ find('[id^="leave_application_start_time"]').set("2018/02/12 09:30")
+ find('[id^="leave_application_start_time"]').set("2018/02/12 18:30")
+ fill_in('事由', with: 'paid_vacation')
+ end
+ click_button '送出'
+ expect(page).to have_content '旅遊假'
+ end
+
+ end
+
+ context "verified" do
+ let!(:user) { FactoryGirl.create(:user, :manager, join_date: Date.current - 1.year - 1.day) }
+ let!(:leave_application) { LeaveApplication.create(user_id: user.id, leave_type: 'maternity', start_time: Time.zone.local(Time.current.year, 8, 15, 9, 30, 0), end_time: Time.zone.local(Time.current.year, 8, 15, 18, 30, 0), description: 'test') }
+ let!(:leave_application_paid_vaca) { LeaveApplication.create(user_id: user.id, leave_type: 'paid_vacation', start_time: Time.zone.local(Time.current.year, 8, 15, 9, 30, 0), end_time: Time.zone.local(Time.current.year, 8, 15, 18, 30, 0), description: 'test') }
+
+ before :each do
+ visit '/users/sign_in'
+ login user.login_name, user.password
+ end
+
+ scenario "menstrual" do
+ visit "/backend/leave_applications/#{leave_application.id}/verify"
+
+ expect(page).to have_content '新增額度'
+ end
+
+ scenario "paid_vacation" do
+ visit "/backend/leave_applications/#{leave_application_vaca.id}/verify"
+ expect(page).to have_content '新增額度'
+ end
+
+ end
+
+ private
+
+ def login(email, password)
+ fill_in "員工帳號", with: email
+ fill_in "密碼", with: password
+ click_button "送出"
+ end
+end
diff --git a/spec/mailers/information_spec.rb b/spec/mailers/information_spec.rb
new file mode 100644
index 00000000..e895f114
--- /dev/null
+++ b/spec/mailers/information_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe InformationMailer, type: :mailer do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/mailers/previews/information_preview.rb b/spec/mailers/previews/information_preview.rb
new file mode 100644
index 00000000..b5fa3ae6
--- /dev/null
+++ b/spec/mailers/previews/information_preview.rb
@@ -0,0 +1,3 @@
+# Preview all emails at http://localhost:3000/rails/mailers/information
+class InformationPreview < ActionMailer::Preview
+end
diff --git a/spec/mailers/previews/user_preview.rb b/spec/mailers/previews/user_preview.rb
new file mode 100644
index 00000000..afe9d42b
--- /dev/null
+++ b/spec/mailers/previews/user_preview.rb
@@ -0,0 +1,3 @@
+# Preview all emails at http://localhost:3000/rails/mailers/user
+class UserPreview < ActionMailer::Preview
+end
diff --git a/spec/mailers/user_spec.rb b/spec/mailers/user_spec.rb
new file mode 100644
index 00000000..ac8c5f14
--- /dev/null
+++ b/spec/mailers/user_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe UserMailer, type: :mailer do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/models/leave_application_spec.rb b/spec/models/leave_application_spec.rb
index 803641ba..8519b5db 100644
--- a/spec/models/leave_application_spec.rb
+++ b/spec/models/leave_application_spec.rb
@@ -20,11 +20,11 @@
end
describe 'validation' do
- let(:params) { FactotyGirl.attributes_for(:leave_application) }
+ # let(:params) { FactoryGirl.attributes_for(:leave_application) }
subject { described_class.new(params) }
context 'has a valid factory' do
- subject { build(:leave_application, :with_leave_time, :annual) }
+ subject { build(:leave_application, :with_leave_time, :personal) }
it { expect(subject).to be_valid }
end
@@ -42,14 +42,14 @@
leave = LeaveApplication.new(
start_time: start_time,
end_time: one_hour_later,
- leave_type: 'sick'
+ leave_type: 'fullpaid_sick'
)
expect(leave).to be_invalid
expect(leave.errors.messages[:description].first).to eq '請簡述原因'
end
it 'hours應為正整數' do
- leave = LeaveApplication.new start_time: start_time, leave_type: 'sick', description: 'test'
+ leave = LeaveApplication.new start_time: start_time, leave_type: 'fullpaid_sick', description: 'test'
leave.end_time = one_hour_ago
expect(leave).to be_invalid
expect(leave.errors.messages[:start_time].first).to eq '開始時間必須早於結束時間'
@@ -84,13 +84,13 @@
User.skip_callback(:create, :after, :auto_assign_leave_time)
create(:leave_time, :annual, user: user, quota: 50, usable_hours: 50, effective_date: effective_date, expiration_date: expiration_date)
end
- after { User.set_callback(:create, :after, :auto_assign_leave_time) }
+ after { User.set_callback(:create, :after, :auto_assign_leave_time) }
- subject { build(:leave_application, :annual, user: user, start_time: beginning, end_time: ending) }
+ subject { build(:leave_application, :personal, user: user, start_time: beginning, end_time: ending) }
shared_examples 'invalid' do |overlap_section, status|
it "should be invalid when overlaps #{overlap_section} of the #{status} leave application" do
- la = create(:leave_application, :annual, status, user: user, start_time: start_time, end_time: end_time, description: 'test string')
+ la = create(:leave_application, :personal, status, user: user, start_time: start_time, end_time: end_time, description: 'test string')
expect(subject.valid?).to be_falsy
expect(subject.errors[:base]).to include I18n.t(
'activerecord.errors.models.leave_application.attributes.base.overlap_application',
@@ -118,7 +118,7 @@
shared_examples 'valid' do |boundary, status|
it "is valid to overlap on #{boundary} of the other #{status} application" do
- create(:leave_application, :annual, status, user: user, start_time: start_time, end_time: end_time, description: 'test string')
+ create(:leave_application, :personal, status, user: user, start_time: start_time, end_time: end_time, description: 'test string')
expect(subject.valid?).to be_truthy
end
end
@@ -179,6 +179,7 @@
it_should_behave_like 'transitions', from: :pending, to: :approved, with_action: :approve, manager_required: true
it_should_behave_like 'transitions', from: :pending, to: :canceled, with_action: :cancel
it_should_behave_like 'transitions', from: :pending, to: :rejected, with_action: :reject, manager_required: true
+ it_should_behave_like 'transitions', from: :approved, to: :rejected, with_action: :reject, manager_required: true
it_should_behave_like 'transitions', from: :pending, to: :pending, with_action: :revise
it_should_behave_like 'transitions', from: :approved, to: :pending, with_action: :revise
@@ -188,9 +189,9 @@
let(:expiration_date) { Time.zone.local(2017, 6, 30).to_date }
let(:start_time) { Time.zone.local(2017, 6, 1, 9, 30) }
let(:end_time) { Time.zone.local(2017, 6, 5, 12, 30) }
- before { create(:leave_time, :annual, user: user, quota: 100, usable_hours: 100) }
+ before { create(:leave_time, :annual, user: user, quota: 100, usable_hours: 100, effective_date: effective_date, expiration_date: expiration_date) }
it 'can transition from approved to canceled unless LeaveApplication happened already' do
- leave_application = create(:leave_application, :annual, user: user, start_time: start_time, end_time: end_time).reload
+ leave_application = create(:leave_application, :personal, user: user, start_time: start_time, end_time: end_time).reload
leave_application.approve!(create(:user, :hr))
expect(leave_application.happened?).to be_truthy
expect(leave_application.approved?).to be_truthy
@@ -292,10 +293,10 @@
let(:beginning) { effective_date.beginning_of_day }
let(:ending) { expiration_date.end_of_day }
let!(:leave_time) { create(:leave_time, :annual, user: user, quota: 100, usable_hours: 100, effective_date: effective_date, expiration_date: expiration_date) }
- let!(:pending) { create(:leave_application, :annual, user: user, start_time: Time.zone.local(2017, 5, 2, 9, 30), end_time: Time.zone.local(2017, 5, 4, 12, 30)) }
- let!(:approved) { create(:leave_application, :annual, :approved, user: user, start_time: Time.zone.local(2017, 5, 9, 9, 30), end_time: Time.zone.local(2017, 5, 11, 12, 30)) }
- let!(:canceled) { create(:leave_application, :annual, :canceled, user: user, start_time: Time.zone.local(2017, 5, 16, 9, 30), end_time: Time.zone.local(2017, 5, 18, 12, 30)) }
- let!(:rejected) { create(:leave_application, :annual, :rejected, user: user, start_time: Time.zone.local(2017, 5, 23, 9, 30), end_time: Time.zone.local(2017, 5, 25, 12, 30)) }
+ let!(:pending) { create(:leave_application, :personal, user: user, start_time: Time.zone.local(2017, 5, 2, 9, 30), end_time: Time.zone.local(2017, 5, 4, 12, 30)) }
+ let!(:approved) { create(:leave_application, :personal, :approved, user: user, start_time: Time.zone.local(2017, 5, 9, 9, 30), end_time: Time.zone.local(2017, 5, 11, 12, 30)) }
+ let!(:canceled) { create(:leave_application, :personal, :canceled, user: user, start_time: Time.zone.local(2017, 5, 16, 9, 30), end_time: Time.zone.local(2017, 5, 18, 12, 30)) }
+ let!(:rejected) { create(:leave_application, :personal, :rejected, user: user, start_time: Time.zone.local(2017, 5, 23, 9, 30), end_time: Time.zone.local(2017, 5, 25, 12, 30)) }
after { User.set_callback(:create, :after, :auto_assign_leave_time) }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index bf7a1799..2d3116c5 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -73,7 +73,8 @@
end
end
it_should_behave_like 'different roles create LeaveTime with different leave_type', %i(manager hr employee fulltime), %w(annual personal fullpaid_sick halfpaid_sick remote)
- it_should_behave_like 'different roles create LeaveTime with different leave_type', %i(intern contractor parttime), %w(personal fullpaid_sick halfpaid_sick remote)
+ it_should_behave_like 'different roles create LeaveTime with different leave_type', %i(intern), %w(personal fullpaid_sick halfpaid_sick remote)
+ it_should_behave_like 'different roles create LeaveTime with different leave_type', %i(contractor), %w(personal)
shared_examples 'specific roles should not create any LeaveTime' do |roles|
roles.each do |role|
@@ -96,7 +97,7 @@
end
all_roles = %i(manager hr employee intern)
it_should_behave_like 'leave_type created with specific quota', all_roles, 'personal', 112
- it_should_behave_like 'leave_type created with specific quota', all_roles, 'remote', 16
+ it_should_behave_like 'leave_type created with specific quota', all_roles, 'remote', 8
it_should_behave_like 'leave_type created with specific quota', all_roles, 'fullpaid_sick', 56
it_should_behave_like 'leave_type created with specific quota', all_roles, 'halfpaid_sick', 184
@@ -107,7 +108,7 @@
it 'should create LeaveTime of the user if specified assign_leave_time and assign_date' do
user = create(:user, :fulltime)
- expect(user.leave_times.any?).to be_truthy
+ expect(user.leave_times.any?).to be_truthy
end
it 'should have error message when assign_leave_time is true while assign_date is nil' do
diff --git a/spec/observers/leave_application_observer_spec.rb b/spec/observers/leave_application_observer_spec.rb
index f27e1c5b..afd781dd 100644
--- a/spec/observers/leave_application_observer_spec.rb
+++ b/spec/observers/leave_application_observer_spec.rb
@@ -7,7 +7,7 @@
let(:start_time) { Time.zone.local(2017, 5, 2, 9, 30) }
let(:end_time) { Time.zone.local(2017, 5, 5, 10, 30) }
let(:total_leave_hours) { Daikichi::Config::Biz.within(start_time, end_time).in_hours }
- let(:leave_application) { create(:leave_application, :annual, user: user, start_time: start_time, end_time: end_time) }
+ let(:leave_application) { create(:leave_application, :personal, user: user, start_time: start_time, end_time: end_time) }
before { User.skip_callback(:create, :after, :auto_assign_leave_time) }
after { User.set_callback(:create, :after, :auto_assign_leave_time) }
@@ -17,14 +17,15 @@
context 'after_create' do
it 'should successfully create LeaveTimeUsage on sufficient LeaveTime hours' do
leave_time_usage = leave_application.leave_time_usages.first
+ total_used_hours = leave_application.leave_time_usages.map(&:used_hours).sum
leave_time.reload
- expect(leave_time_usage.used_hours).to eq total_leave_hours
+ expect(total_used_hours).to eq total_leave_hours
expect(leave_time_usage.leave_time).to eq leave_time
expect(leave_time.locked_hours).to eq total_leave_hours
end
it 'should not create LeaveTimeUsage when insufficient LeaveTime hours' do
- la = create(:leave_application, :annual, user: user, start_time: start_time, end_time: end_time + 1.hour)
+ la = create(:leave_application, :personal, user: user, start_time: start_time, end_time: end_time + 1.hour)
expect(la.errors.any?).to be_truthy
expect(la.leave_time_usages.any?).to be false
expect(leave_time.usable_hours).to eq total_leave_hours
@@ -33,10 +34,11 @@
context 'after_update' do
it 'should recreate LeaveTimeUsage only when AASM event is "revise"' do
- la = create(:leave_application, :annual, :approved, user: user, start_time: start_time, end_time: end_time)
+ la = create(:leave_application, :personal, :approved, user: user, start_time: start_time, end_time: end_time)
leave_time_usage = la.leave_time_usages.first
+ total_used_hours = la.leave_time_usages.map(&:used_hours).sum
leave_time.reload
- expect(leave_time_usage.used_hours).to eq total_leave_hours
+ expect(total_used_hours).to eq total_leave_hours
expect(leave_time_usage.leave_time).to eq leave_time
expect(leave_time.used_hours).to eq total_leave_hours
@@ -44,38 +46,39 @@
la.revise!
leave_time_usage = la.leave_time_usages.first
leave_time.reload
- expect(leave_time_usage.used_hours).to eq (total_leave_hours - 1)
+ total_used_hours = la.leave_time_usages.map(&:used_hours).sum
+ expect(total_used_hours).to eq(total_leave_hours - 1)
expect(leave_time_usage.leave_time).to eq leave_time
- expect(leave_time.locked_hours).to eq (total_leave_hours - 1)
+ expect(leave_time.locked_hours).to eq(total_leave_hours - 1)
end
end
end
describe '.hours_update' do
let(:quota) { 100 }
- let!(:leave_time) { create(:leave_time, :annual, user: user, quota: quota, usable_hours: quota, effective_date: effective_date, expiration_date: expiration_date) }
+ let!(:leave_time) { create(:leave_time, :annual, user: user, quota: quota, usable_hours: quota, effective_date: effective_date, expiration_date: expiration_date) }
context 'before_update' do
describe 'AASM "approve" event' do
it 'should transfer locked_hours to used_hours' do
leave_time_usage = leave_application.leave_time_usages.first
leave_time.reload
expect(leave_time_usage.leave_time).to eq leave_time
- expect(leave_time.usable_hours).to eq (quota - total_leave_hours)
+ expect(leave_time.usable_hours).to eq(quota - total_leave_hours)
expect(leave_time.locked_hours).to eq total_leave_hours
leave_application.reload.approve! user
leave_time.reload
- expect(leave_time.usable_hours).to eq (quota - total_leave_hours)
+ expect(leave_time.usable_hours).to eq(quota - total_leave_hours)
expect(leave_time.used_hours).to eq total_leave_hours
end
end
- shared_examples 'return locked_hours back to used_hours' do |event, required_user|
+ shared_examples 'return locked_hours back to usable_hours' do |event, required_user|
describe "AASM \"#{event}\" event" do
- it "should return locked_hours back to used_hours when #{event}ed" do
+ it "should return locked_hours back to usable_hours when pending to #{event}ed" do
leave_time_usage = leave_application.leave_time_usages.first
leave_time.reload
expect(leave_time_usage.leave_time).to eq leave_time
- expect(leave_time.usable_hours).to eq (quota - total_leave_hours)
+ expect(leave_time.usable_hours).to eq(quota - total_leave_hours)
expect(leave_time.locked_hours).to eq total_leave_hours
leave_application.reload.send :"#{event}!", (required_user ? user : nil)
leave_time.reload
@@ -85,8 +88,27 @@
end
end
- it_should_behave_like 'return locked_hours back to used_hours', :reject, true
- it_should_behave_like 'return locked_hours back to used_hours', :cancel
+ describe 'AASM "reject" event' do
+ it_should_behave_like 'return locked_hours back to usable_hours', :reject, true
+
+ it 'should return used_hours back to usable_hours when approved to rejected' do
+ leave_application.reload.approve! user
+ leave_time.reload
+ expect(leave_time.usable_hours).to eq(quota - total_leave_hours)
+ expect(leave_time.used_hours).to eq total_leave_hours
+ expect(leave_time.locked_hours).to be_zero
+ leave_application.reload.reject! user
+ leave_time.reload
+ expect(leave_time.usable_hours).to eq quota
+ expect(leave_time.used_hours).to be_zero
+ expect(leave_time.locked_hours).to be_zero
+ expect(leave_application.leave_time_usages).to be_empty
+ end
+ end
+
+ describe 'AASM "cancel" event' do
+ it_should_behave_like 'return locked_hours back to usable_hours', :cancel
+ end
describe 'AASM "revise" event' do
shared_examples 'revise attribute' do |attribute, value|
@@ -96,10 +118,11 @@
leave_application.reload
used_hours = Daikichi::Config::Biz.within(leave_application.start_time, leave_application.end_time).in_hours
leave_time_usage = leave_application.leave_time_usages.first
+ total_used_hours = leave_application.leave_time_usages.map(&:used_hours).sum
leave_time.reload
expect(leave_application.hours).to eq used_hours
- expect(leave_application.status).to eq "pending"
- expect(leave_time_usage.used_hours).to eq used_hours
+ expect(leave_application.status).to eq 'pending'
+ expect(total_used_hours).to eq used_hours
expect(leave_time_usage.leave_time).to eq leave_time
expect(leave_time.usable_hours).to eq quota - used_hours
expect(leave_time.locked_hours).to eq used_hours
@@ -107,15 +130,15 @@
end
context 'pending application' do
- let!(:leave_application) { create(:leave_application, :annual, user: user, start_time: start_time, end_time: end_time) }
+ let!(:leave_application) { create(:leave_application, :personal, user: user, start_time: start_time, end_time: end_time) }
it_should_behave_like 'revise attribute', :start_time, Time.zone.local(2017, 5, 3, 9, 30)
it_should_behave_like 'revise attribute', :end_time, Time.zone.local(2017, 5, 3, 12, 30)
it_should_behave_like 'revise attribute', :description, Faker::Lorem.paragraph
end
context 'approved application' do
- let!(:leave_application) do
- create(:leave_application, :annual, user: user, start_time: start_time, end_time: end_time)
+ let!(:leave_application) do
+ create(:leave_application, :personal, user: user, start_time: start_time, end_time: end_time)
user.leave_applications.first.approve! user
user.leave_applications.first
end
diff --git a/spec/services/leave_time_batch_builder_spec.rb b/spec/services/leave_time_batch_builder_spec.rb
index 3189f513..e13a44fa 100644
--- a/spec/services/leave_time_batch_builder_spec.rb
+++ b/spec/services/leave_time_batch_builder_spec.rb
@@ -5,6 +5,7 @@
let(:monthly_lead_days) { Settings.leed_days.monthly }
let(:join_date_based_leed_days) { Settings.leed_days.join_date_based }
let(:monthly_leave_types) { Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'monthly' } }
+ let(:weekly_leave_types) { Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'weekly' } }
let(:join_date_based_leave_types) { Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'join_date_based' } }
let(:seniority_based_leave_types) do
join_date_based_leave_types.select do |lt|
@@ -18,7 +19,8 @@
context 'is forced' do
let!(:fulltime) { FactoryGirl.create(:user, :fulltime, join_date: Date.current - 1.year - 1.day) }
- let!(:parttime) { FactoryGirl.create(:user, :parttime, join_date: Date.current - 1.year - 1.day) }
+ let!(:parttime) { FactoryGirl.create(:user, :intern, join_date: Date.current - 1.year - 1.day) }
+ let!(:contractor) { FactoryGirl.create(:user, :contractor, join_date: Date.current - 1.year - 1.day) }
let!(:user) { FactoryGirl.create(:user, join_date: Date.current - 1.year - 1.day) }
before do
@@ -26,36 +28,39 @@
end
it 'should run join_date_based_import and monthly import with prebuild option for all users' do
- leave_times = LeaveTime.where(user_id: [fulltime.id, parttime.id, user.id])
- expect(leave_times.reload.size).to eq((monthly_leave_types.size + join_date_based_leave_types.size) * 3 - seniority_based_leave_types.size)
- monthly_leave_time = leave_times.find { |x| x.leave_type == monthly_leave_types.first.first }
- expect(monthly_leave_time.effective_date).to eq Time.zone.today
- expect(monthly_leave_time.expiration_date).to eq Time.zone.today.end_of_month
+ unless monthly_leave_types.blank?
+ leave_times = LeaveTime.where(user_id: [fulltime.id, parttime.id, user.id, contractor.id])
+ expect(leave_times.reload.size).to eq(1 + (monthly_leave_types.size + join_date_based_leave_types.size) * 3 - seniority_based_leave_types.size)
+ monthly_leave_time = leave_times.find { |x| x.leave_type == monthly_leave_types.first.first }
+ expect(monthly_leave_time.effective_date).to eq Time.zone.today
+ expect(monthly_leave_time.expiration_date).to eq Time.zone.today.end_of_month
- join_date_based_leave_time = leave_times.find { |x| x.leave_type == join_date_based_leave_types.first.first }
- join_anniversary = user.next_join_anniversary
- expect(join_date_based_leave_time.effective_date).to eq join_anniversary
- expect(join_date_based_leave_time.expiration_date).to eq join_anniversary + 1.year - 1.day
+ join_date_based_leave_time = leave_times.find { |x| x.leave_type == join_date_based_leave_types.first.first }
+ join_anniversary = user.next_join_anniversary
+ expect(join_date_based_leave_time.effective_date).to eq join_anniversary
+ expect(join_date_based_leave_time.expiration_date).to eq join_anniversary + 1.year - 1.day
+ end
end
end
context 'not forced' do
let!(:fulltime) { FactoryGirl.create(:user, :fulltime, join_date: join_date) }
- let!(:parttime) { FactoryGirl.create(:user, :parttime, join_date: join_date) }
+ let!(:parttime) { FactoryGirl.create(:user, :intern, join_date: join_date) }
+ let!(:contractor) { FactoryGirl.create(:user, :contractor, join_date: join_date) }
let!(:user) { FactoryGirl.create(:user, join_date: join_date - 1.day) }
+ let!(:datetime) { Time.zone.local(2017, 5, 4, 9, 30) }
context 'end of working month' do
- let(:join_date) { Daikichi::Config::Biz.time(monthly_lead_days, :days).before(Daikichi::Config::Biz.periods.before(Time.current.end_of_month).first.end_time) - 2.years + join_date_based_leed_days.days }
-
+ let(:join_date) { Daikichi::Config::Biz.time(monthly_lead_days, :days).before(Daikichi::Config::Biz.periods.before(datetime.end_of_month).first.end_time) - 2.years + join_date_based_leed_days.days }
before do
- Timecop.freeze(Daikichi::Config::Biz.time(monthly_lead_days, :days).before(Daikichi::Config::Biz.periods.before(Time.current.end_of_month).first.end_time))
+ Timecop.freeze(Daikichi::Config::Biz.time(monthly_lead_days, :days).before(Daikichi::Config::Biz.periods.before(datetime.end_of_month).first.end_time))
described_class.new.automatically_import
end
after { Timecop.return }
it 'should run join date based import only for users that join_date anniversary is comming and monthly import without prebuild option for all users' do
- leave_times = LeaveTime.where(user_id: [fulltime.id, parttime.id, user.id])
- expect(leave_times.reload.size).to eq(monthly_leave_types.size * 3 + join_date_based_leave_types.size * 2 - seniority_based_leave_types.size)
+ leave_times = LeaveTime.where(user_id: [fulltime.id, parttime.id, user.id, contractor.id])
+ expect(leave_times.reload.size).to eq(1 + weekly_leave_types.size * 3 + join_date_based_leave_types.size * 2 - seniority_based_leave_types.size)
join_date_based_leave_time = leave_times.find { |x| x.leave_type == join_date_based_leave_types.first.first }
join_anniversary = fulltime.next_join_anniversary
@@ -66,16 +71,19 @@
context 'not end of working month' do
let(:join_date) { Date.current.end_of_month + 3.days - 2.years + join_date_based_leed_days.days }
-
before do
- Timecop.freeze(Date.current.end_of_month + 3.days)
+ if (Date.current.end_of_month + 3.days - 2.years).month <= 2 && (Date.current.end_of_month + 3.days - 2.years).leap?
+ Timecop.freeze(Date.current.end_of_month + 2.days)
+ else
+ Timecop.freeze(Date.current.end_of_month + 3.days)
+ end
described_class.new.automatically_import
end
after { Timecop.return }
it 'should run join date based import for users that join_date anniversary is comming only' do
- leave_times = LeaveTime.where(user_id: [fulltime.id, parttime.id, user.id])
- expect(leave_times.reload.size).to eq(join_date_based_leave_types.size * 2 - seniority_based_leave_types.size)
+ leave_times = LeaveTime.where(user_id: [fulltime.id, parttime.id, user.id, contractor.id])
+ expect(leave_times.reload.size).to eq(1 + join_date_based_leave_types.size * 2 - seniority_based_leave_types.size)
join_date_based_leave_time = leave_times.find { |x| x.leave_type == join_date_based_leave_types.first.first }
join_anniversary = fulltime.next_join_anniversary
diff --git a/spec/services/leave_time_builder_spec.rb b/spec/services/leave_time_builder_spec.rb
index a7dce2db..800dc23f 100644
--- a/spec/services/leave_time_builder_spec.rb
+++ b/spec/services/leave_time_builder_spec.rb
@@ -2,8 +2,9 @@
require 'rails_helper'
describe LeaveTimeBuilder do
- let(:user) { FactoryGirl.create(:user) }
+ let(:user) { FactoryGirl.create(:user, assign_date: Time.zone.today) }
let(:monthly_leave_types) { Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'monthly' } }
+ let(:weekly_leave_types) { Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'weekly' } }
let(:join_date_based_leave_types) { Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'join_date_based' } }
let(:seniority_based_leave_types) do
join_date_based_leave_types.select do |lt|
@@ -16,7 +17,7 @@
context 'fulltime employee' do
context 'import join date based LeaveTime with specific assign_date' do
let(:user) { User.new(FactoryGirl.attributes_for(:user, :fulltime)) }
- let(:current_date) { Date.parse "2017/06/14" }
+ let(:current_date) { Date.parse '2017/06/14' }
before do
Timecop.freeze current_date
@@ -80,22 +81,22 @@ def join_date_based_leave_times(user)
expect(leave_times.count).to eq 1
expect(leave_times.first.effective_date).to eq Date.parse '2017/07/14'
expect(leave_times.first.expiration_date).to eq Date.parse '2018/05/13'
- end
+ end
end
it 'should build LeaveTime based on assign_date when assign_date is after current date and after this year leed day' do
- user.join_date = current_date + join_date_based_leed_day - 2.year
+ user.join_date = current_date + join_date_based_leed_day - 2.years
user.assign_date = (current_date + join_date_based_leed_day).to_s
user.save!
join_date_based_leave_times(user) do |leave_times|
expect(leave_times.count).to eq 1
- expect(leave_times.first.effective_date).to eq Date.parse '2017/07/24'
- expect(leave_times.first.expiration_date).to eq Date.parse '2018/07/23'
+ expect(leave_times.first.effective_date).to eq Date.parse '2017/08/13'
+ expect(leave_times.first.expiration_date).to eq Date.parse '2018/08/12'
end
end
it 'should build LeaveTime based on assign_date when assign_date is after current date and before this year leed day' do
- user.join_date = current_date + join_date_based_leed_day - 2.year + 1.day
+ user.join_date = current_date + join_date_based_leed_day - 2.years + 1.day
user.assign_date = (current_date + join_date_based_leed_day + 1.day).to_s
user.save!
join_date_based_leave_times(user) do |leave_times|
@@ -113,8 +114,8 @@ def join_date_based_leave_times(user)
user.save!
join_date_based_leave_times(user) do |leave_times|
expect(leave_times.count).to eq 1
- expect(leave_times.first.effective_date).to eq Date.parse '2017/07/24'
- expect(leave_times.first.expiration_date).to eq Date.parse '2018/07/23'
+ expect(leave_times.first.effective_date).to eq Date.parse '2017/08/13'
+ expect(leave_times.first.expiration_date).to eq Date.parse '2018/08/12'
end
end
@@ -124,8 +125,8 @@ def join_date_based_leave_times(user)
user.save!
join_date_based_leave_times(user) do |leave_times|
expect(leave_times.count).to eq 1
- expect(leave_times.first.effective_date).to eq Date.parse '2017/07/25'
- expect(leave_times.first.expiration_date).to eq Date.parse '2018/07/24'
+ expect(leave_times.first.effective_date).to eq Date.parse '2017/08/14'
+ expect(leave_times.first.expiration_date).to eq Date.parse '2018/08/13'
end
end
end
@@ -133,12 +134,12 @@ def join_date_based_leave_times(user)
context 'import monthly LeaveTime with specific assign_date' do
let(:user) { User.new(FactoryGirl.attributes_for(:user, :fulltime)) }
- let(:current_date) { Date.parse "2017/06/14" }
+ let(:current_date) { Date.parse '2017/06/14' }
join_date = Date.parse('2017/06/14') - 1.year - 1.month
before_join_date = join_date - 1.month
after_join_date_before_current_date = join_date + 1.month
let(:after_current_date) { current_date + 1.month }
-
+
before do
Timecop.freeze current_date
user.assign_leave_time = '1'
@@ -174,7 +175,7 @@ def monthly_leave_times(user)
end
end
end
-
+
it_should_behave_like 'build monthly LeaveTime', based_on: 'join_date', when: 'assign_date is before join_date', assign_date: before_join_date
it_should_behave_like 'build monthly LeaveTime', based_on: 'join_date', when: 'assign_date is on join_date', assign_date: join_date
it_should_behave_like 'build monthly LeaveTime', based_on: 'assign_date', when: 'assign_date is after join_date and before current_date', assign_date: after_join_date_before_current_date
@@ -190,8 +191,8 @@ def monthly_leave_times(user)
context 'partime employee' do
context 'import join date based LeaveTime with specific assign_date' do
- let(:user) { User.new(FactoryGirl.attributes_for(:user, :parttime)) }
- let(:current_date) { Date.parse "2017/06/14" }
+ let(:user) { User.new(FactoryGirl.attributes_for(:user, :intern)) }
+ let(:current_date) { Date.parse '2017/06/14' }
before do
Timecop.freeze current_date
@@ -271,11 +272,11 @@ def join_date_based_leave_times(user)
expect(leave_times.count).to eq 1
expect(leave_times.first.effective_date).to eq Date.parse '2017/07/14'
expect(leave_times.first.expiration_date).to eq Date.parse '2018/05/13'
- end
+ end
end
it 'should build LeaveTime based on assign_date when assign_date is after current date and after this year leed day' do
- user.join_date = current_date + join_date_based_leed_day - 2.year
+ user.join_date = current_date + join_date_based_leed_day - 2.years
user.assign_date = (current_date + join_date_based_leed_day).to_s
user.save!
join_date_based_leave_times(user) do |leave_times, leave_type|
@@ -284,13 +285,13 @@ def join_date_based_leave_times(user)
next
end
expect(leave_times.count).to eq 1
- expect(leave_times.first.effective_date).to eq Date.parse '2017/07/24'
- expect(leave_times.first.expiration_date).to eq Date.parse '2018/07/23'
+ expect(leave_times.first.effective_date).to eq Date.parse '2017/08/13'
+ expect(leave_times.first.expiration_date).to eq Date.parse '2018/08/12'
end
end
it 'should build LeaveTime based on assign_date when assign_date is after current date and before this year leed day' do
- user.join_date = current_date + join_date_based_leed_day - 2.year + 1.day
+ user.join_date = current_date + join_date_based_leed_day - 2.years + 1.day
user.assign_date = (current_date + join_date_based_leed_day + 1.day).to_s
user.save!
join_date_based_leave_times(user) do |leave_times, leave_type|
@@ -316,8 +317,8 @@ def join_date_based_leave_times(user)
next
end
expect(leave_times.count).to eq 1
- expect(leave_times.first.effective_date).to eq Date.parse '2017/07/24'
- expect(leave_times.first.expiration_date).to eq Date.parse '2018/07/23'
+ expect(leave_times.first.effective_date).to eq Date.parse '2017/08/13'
+ expect(leave_times.first.expiration_date).to eq Date.parse '2018/08/12'
end
end
@@ -331,8 +332,8 @@ def join_date_based_leave_times(user)
next
end
expect(leave_times.count).to eq 1
- expect(leave_times.first.effective_date).to eq Date.parse '2017/07/25'
- expect(leave_times.first.expiration_date).to eq Date.parse '2018/07/24'
+ expect(leave_times.first.effective_date).to eq Date.parse '2017/08/14'
+ expect(leave_times.first.expiration_date).to eq Date.parse '2018/08/13'
end
end
end
@@ -340,12 +341,12 @@ def join_date_based_leave_times(user)
context 'import monthly LeaveTime with specific assign_date' do
let(:user) { User.new(FactoryGirl.attributes_for(:user, :fulltime)) }
- let(:current_date) { Date.parse "2017/06/14" }
+ let(:current_date) { Date.parse '2017/06/14' }
join_date = Date.parse('2017/06/14') - 1.year - 1.month
before_join_date = join_date - 1.month
after_join_date_before_current_date = join_date + 1.month
let(:after_current_date) { current_date + 1.month }
-
+
before do
Timecop.freeze current_date
user.assign_leave_time = '1'
@@ -381,7 +382,7 @@ def monthly_leave_times(user)
end
end
end
-
+
it_should_behave_like 'build monthly LeaveTime', based_on: 'join_date', when: 'assign_date is before join_date', assign_date: before_join_date
it_should_behave_like 'build monthly LeaveTime', based_on: 'join_date', when: 'assign_date is on join_date', assign_date: join_date
it_should_behave_like 'build monthly LeaveTime', based_on: 'assign_date', when: 'assign_date is after join_date and before current_date', assign_date: after_join_date_before_current_date
@@ -428,13 +429,13 @@ def monthly_leave_times(user)
end
context 'parttime employee' do
- let(:user) { FactoryGirl.create(:user, :parttime) }
+ let(:user) { FactoryGirl.create(:user, :intern) }
it 'should not get seniority_based leave_times' do
leave_times = user.leave_times
expect(leave_times.size).to eq join_date_based_leave_types.size - seniority_based_leave_types.size
leave_time = leave_times.first
- initial_quota = join_date_based_leave_types.select { |lt| lt.first == leave_time.leave_type }.first.second['quota'] * 8
+ initial_quota = join_date_based_leave_types.find { |lt| lt.first == leave_time.leave_type }.second['quota'] * 8
expect(leave_time.quota).to eq initial_quota
expect(leave_time.usable_hours).to eq initial_quota
expect(leave_time.used_hours).to eq 0
@@ -459,15 +460,17 @@ def monthly_leave_times(user)
end
it 'is build for the comming month' do
- leave_times = user.leave_times.reload
- expect(leave_times.size).to eq monthly_leave_types.size
- leave_time = leave_times.first
- initial_quota = monthly_leave_types.select { |lt| lt.first == leave_time.leave_type }.first.second['quota'] * 8
- expect(leave_time.quota).to eq initial_quota
- expect(leave_time.usable_hours).to eq initial_quota
- expect(leave_time.used_hours).to eq 0
- expect(leave_time.effective_date).to eq Time.zone.today.next_month.beginning_of_month
- expect(leave_time.expiration_date).to eq Time.zone.today.next_month.end_of_month
+ unless monthly_leave_types.blank?
+ leave_times = user.leave_times.reload
+ expect(leave_times.size).to eq monthly_leave_types.size
+ leave_time = leave_times.first
+ initial_quota = monthly_leave_types.find { |lt| lt.first == leave_time.leave_type }.second['quota'] * 8
+ expect(leave_time.quota).to eq initial_quota
+ expect(leave_time.usable_hours).to eq initial_quota
+ expect(leave_time.used_hours).to eq 0
+ expect(leave_time.effective_date).to eq Time.zone.today.next_month.beginning_of_month
+ expect(leave_time.expiration_date).to eq Time.zone.today.next_month.end_of_month
+ end
end
end
@@ -477,15 +480,67 @@ def monthly_leave_times(user)
end
it 'is build for current month' do
+ unless monthly_leave_types.blank?
+ leave_times = user.leave_times.reload
+ expect(leave_times.size).to eq monthly_leave_types.size
+ leave_time = leave_times.first
+ initial_quota = monthly_leave_types.find { |lt| lt.first == leave_time.leave_type }.second['quota'] * 8
+ expect(leave_time.quota).to eq initial_quota
+ expect(leave_time.usable_hours).to eq initial_quota
+ expect(leave_time.used_hours).to eq 0
+ expect(leave_time.effective_date).to eq Time.zone.today
+ expect(leave_time.expiration_date).to eq Time.zone.today.end_of_month
+ end
+ end
+ end
+ end
+
+ describe '.weekly_import' do
+ before do
+ User.skip_callback(:create, :after, :auto_assign_leave_time)
+ end
+
+ after do
+ User.set_callback(:create, :after, :auto_assign_leave_time)
+ end
+
+ it 'create new user' do
+ LeaveTimeBuilder.new(user).weekly_import(by_assign_date: true)
+ leave_times = user.leave_times.reload
+ expect(leave_times.size).to eq weekly_leave_types.size * 4
+ date = Time.zone.today
+ leave_time = leave_times.first
+ initial_quota = weekly_leave_types.find { |lt| lt.first == leave_time.leave_type }.second['quota'] * 8
+ expect(leave_time.quota).to eq initial_quota
+ expect(leave_time.usable_hours).to eq initial_quota
+ expect(leave_time.used_hours).to eq 0
+ expect(leave_time.effective_date).to eq user.assign_date
+ expect(leave_time.expiration_date).to eq user.assign_date.end_of_week
+ end
+
+ it 'build leave time for after four weeks if today is Monday' do
+ if Time.zone.today.monday?
+ LeaveTimeBuilder.new(user).weekly_import
leave_times = user.leave_times.reload
- expect(leave_times.size).to eq monthly_leave_types.size
+ expect(leave_times.size).to eq weekly_leave_types.size
+ date = Time.zone.today
leave_time = leave_times.first
- initial_quota = monthly_leave_types.select { |lt| lt.first == leave_time.leave_type }.first.second['quota'] * 8
+ initial_quota = weekly_leave_types.find { |lt| lt.first == leave_time.leave_type }.second['quota'] * 8
expect(leave_time.quota).to eq initial_quota
expect(leave_time.usable_hours).to eq initial_quota
expect(leave_time.used_hours).to eq 0
- expect(leave_time.effective_date).to eq Time.zone.today
- expect(leave_time.expiration_date).to eq Time.zone.today.end_of_month
+ expect(leave_time.effective_date).to eq (date + 4.week).beginning_of_week
+ expect(leave_time.expiration_date).to eq (date + 4.week).end_of_week
+ end
+ end
+
+ it 'will not build leave time for after four weeks because today is not Monday' do
+ unless Time.zone.today.monday?
+ LeaveTimeBuilder.new(user).weekly_import
+ leave_times = user.leave_times.reload
+ expect(leave_times.size).to eq 0
+ leave_time = leave_times.first
+ expect(leave_time).to eq nil
end
end
end
diff --git a/spec/services/leave_time_summary_service_spec.rb b/spec/services/leave_time_summary_service_spec.rb
new file mode 100644
index 00000000..6b8d1ca1
--- /dev/null
+++ b/spec/services/leave_time_summary_service_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+require 'rails_helper'
+
+describe LeaveTimeSummaryService do
+ before { Timecop.freeze(Time.zone.local(2018, 1, 2)) }
+ let!(:manager) { create(:user, :manager) }
+ let!(:user) { create(:user, :employee, join_date: Time.zone.local(2018, 1, 2)) }
+ let!(:user2) { create(:user, :employee, join_date: Time.zone.local(2016, 1, 2)) }
+
+ describe 'summary total leave_time' do
+ context 'same leave type' do
+ let(:start_time) { Time.zone.local(2018, 1, 5, 9, 30) }
+ let(:end_time) { Time.zone.local(2018, 1, 10, 18, 30) }
+ it 'should calculate total leave' do
+ leave_application = create(:leave_application, :personal, user: user, start_time: start_time, end_time: end_time).reload
+ leave_application.approve!(manager)
+ leave_application = create(:leave_application, :personal, user: user2, start_time: start_time, end_time: end_time).reload
+ leave_application.approve!(manager)
+ summary = LeaveTimeSummaryService.new(Date.current.year, Date.current.month).summary
+ expect(summary[user.id]['annual']).to eq 32
+ expect(summary[user2.id]['annual']).to eq 32
+ end
+ end
+
+ context 'different leave type' do
+ let(:personal_start_time) { Time.zone.local(2018, 1, 18, 9, 30) }
+ let(:personal_end_time) { Time.zone.local(2018, 1, 31, 18, 30) }
+ it 'should calculate total leave times for different leave type' do
+ leave_application = create(:leave_application, user: user, start_time: personal_start_time, end_time: personal_end_time).reload
+ leave_application.approve!(manager)
+ leave_application = create(:leave_application, user: user2, start_time: personal_start_time, end_time: personal_end_time).reload
+ leave_application.approve!(manager)
+ summary = LeaveTimeSummaryService.new(2018, 1).summary
+ expect(summary[user.id]['annual']).to eq 56
+ expect(summary[user.id]['personal']).to eq 24
+ expect(summary[user2.id]['annual']).to eq 80
+ end
+ end
+
+ context 'start time and end time in different month' do
+ let(:start_time) { Time.zone.local(2018, 1, 25, 10, 30) }
+ let(:start_time2) { Time.zone.local(2018, 1, 30, 9, 30) }
+ let(:end_time) { Time.zone.local(2018, 1, 29, 18, 30) }
+ let(:end_time2) { Time.zone.local(2018, 2, 9, 18, 30) }
+ it 'should calculate total sick leave times in specified month' do
+ leave_application = create(:leave_application, :halfpaid_sick, user: user, start_time: start_time, end_time: end_time).reload
+ leave_application.approve!(manager)
+ leave_application = create(:leave_application, :halfpaid_sick, user: user, start_time: start_time2, end_time: end_time2).reload
+ leave_application.approve!(manager)
+ summary = LeaveTimeSummaryService.new(2018, 1).summary
+ expect(summary[user.id]['halfpaid_sick']).to eq 39
+ summary = LeaveTimeSummaryService.new(2018, 2).summary
+ expect(summary[user.id]['halfpaid_sick']).to eq 56
+ end
+
+ it 'should calculate total personal leave times in specified month' do
+ create(:leave_time, :bonus, user: user, quota: 8, usable_hours: 8)
+ leave_application = create(:leave_application, :personal, user: user, start_time: start_time, end_time: end_time).reload
+ leave_application.approve!(manager)
+ leave_application = create(:leave_application, :personal, user: user, start_time: start_time2, end_time: end_time2).reload
+ leave_application.approve!(manager)
+ leave_application = create(:leave_application, :personal, user: user2, start_time: start_time, end_time: end_time).reload
+ leave_application.approve!(manager)
+ leave_application = create(:leave_application, :personal, user: user2, start_time: start_time2, end_time: end_time2).reload
+ leave_application.approve!(manager)
+ summary = LeaveTimeSummaryService.new(2018, 1).summary
+ expect(summary[user.id]['bonus']).to eq 8
+ expect(summary[user.id]['annual']).to eq 31
+ expect(summary[user2.id]['annual']).to eq 39
+ summary = LeaveTimeSummaryService.new(2018, 2).summary
+ expect(summary[user.id]['annual']).to eq 25
+ expect(summary[user.id]['personal']).to eq 31
+ expect(summary[user2.id]['annual']).to eq 41
+ expect(summary[user2.id]['personal']).to eq 15
+ end
+ end
+ end
+end
diff --git a/spec/services/leave_time_usage_builder_spec.rb b/spec/services/leave_time_usage_builder_spec.rb
index 55a3996f..615c304b 100644
--- a/spec/services/leave_time_usage_builder_spec.rb
+++ b/spec/services/leave_time_usage_builder_spec.rb
@@ -4,7 +4,7 @@
let(:user) { create(:user) }
let(:start_time) { Time.zone.local(2017, 5, 4, 9, 30) }
let(:end_time) { Time.zone.local(2017, 5, 9, 12, 30) }
- let(:leave_application) { create(:leave_application, :annual, user: user, start_time: start_time, end_time: end_time) }
+ let(:leave_application) { create(:leave_application, :personal, user: user, start_time: start_time, end_time: end_time) }
let(:total_used_hours) { Daikichi::Config::Biz.within(start_time, end_time).in_hours }
before { User.skip_callback(:create, :after, :auto_assign_leave_time) }
@@ -18,7 +18,7 @@
it 'returns a hash to represent leave time as hours by date' do
builder = described_class.new leave_application
- expect(builder.leave_hours_by_date).to eq ({
+ expect(builder.leave_hours_by_date).to eq({
Date.parse('2017-05-04') => 8,
Date.parse('2017-05-05') => 8,
Date.parse('2017-05-08') => 8,
@@ -36,17 +36,19 @@
before { create(:leave_time, :annual, user: user, quota: quota, usable_hours: quota, effective_date: effective_date, expiration_date: expiration_date) }
it 'should create successfully with sufficient usable hours' do
- leave_application = create(:leave_application, :annual, user: user, start_time: Time.zone.local(2017, 5, 1, 9, 30), end_time: Time.zone.local(2017, 5, 5, 12, 30))
+ leave_application = create(:leave_application, :personal, user: user, start_time: Time.zone.local(2017, 5, 1, 9, 30), end_time: Time.zone.local(2017, 5, 5, 12, 30))
leave_time_usage = leave_application.leave_time_usages.first
+ usage_total_used_hours = leave_application.leave_time_usages.map(&:used_hours).sum
leave_time = leave_time_usage.leave_time
- expect(leave_application.leave_time_usages.size).to eq 1
- expect(leave_time_usage.used_hours).to eq leave_application.hours
- expect(leave_time.usable_hours).to eq (quota - leave_application.hours)
+ work_periods_by_date = Daikichi::Config::Biz.periods.after(leave_application.start_time).timeline.until(leave_application.end_time).to_a.group_by { |wp| wp.start_time.localtime.to_date }.count
+ expect(leave_application.leave_time_usages.size).to eq work_periods_by_date
+ expect(usage_total_used_hours).to eq leave_application.hours
+ expect(leave_time.usable_hours).to eq(quota - leave_application.hours)
expect(leave_time.locked_hours).to eq leave_application.hours
end
it 'should create failed with insufficient usable hours' do
- leave_application = create(:leave_application, :annual, user: user, start_time: Time.zone.local(2017, 5, 1, 9, 30), end_time: Time.zone.local(2017, 5, 31, 12, 30))
+ leave_application = create(:leave_application, :personal, user: user, start_time: Time.zone.local(2017, 5, 1, 9, 30), end_time: Time.zone.local(2017, 5, 31, 12, 30))
leave_time = user.leave_times.first
expect(user.leave_applications).to be_empty
expect(LeaveTimeUsage.where(leave_application: leave_application)).to be_empty
@@ -61,13 +63,14 @@
create(:leave_time, :annual, user: user, quota: 50, usable_hours: 50, effective_date: Date.parse('2017-05-06'), expiration_date: Date.parse('2017-05-10'))
end
- subject { create(:leave_application, :annual, user: user, start_time: Time.zone.local(2017, 5, 3, 9, 30), end_time: Time.zone.local(2017, 5, 12, 12, 30)) }
+ subject { create(:leave_application, :personal, user: user, start_time: Time.zone.local(2017, 5, 3, 9, 30), end_time: Time.zone.local(2017, 5, 12, 12, 30)) }
it 'should create LeaveTimeUsage successfully with sufficent hours' do
create(:leave_time, :annual, user: user, quota: 50, usable_hours: 50, effective_date: Date.parse('2017-05-11'), expiration_date: Date.parse('2017-05-15'))
+ work_periods_by_date = Daikichi::Config::Biz.periods.after(subject.start_time).timeline.until(subject.end_time).to_a.group_by { |wp| wp.start_time.localtime.to_date }.count
expect(subject.errors).to be_empty
expect(user.leave_applications.size).to be 1
- expect(subject.leave_time_usages.size).to be 3
+ expect(subject.leave_time_usages.size).to be work_periods_by_date
end
it 'should failed to create LeaveTimeUsage with insufficient hours' do
@@ -81,7 +84,7 @@
context 'didn\'t completely covered LeaveApplication' do
let(:start_time) { Time.zone.local(2017, 5, 3, 9, 30) }
let(:end_time) { Time.zone.local(2017, 5, 12, 12, 30) }
- subject { create(:leave_application, :annual, user: user, start_time: start_time, end_time: end_time) }
+ subject { create(:leave_application, :personal, user: user, start_time: start_time, end_time: end_time) }
shared_examples 'not covered partially' do |part, lt_params_1, lt_params_2, error_date, lack_hours|
it "create failed with LeaveTimes not covering the #{part} of LeaveApplication" do
@@ -104,14 +107,15 @@
let(:nearly_expired_date) { expiration_date - 1.day }
let(:start_time) { Time.zone.local(2017, 5, 3, 9, 30) }
let(:end_time) { Time.zone.local(2017, 5, 12, 12, 30) }
- subject { create(:leave_application, :annual, user: user, start_time: start_time, end_time: end_time) }
+ subject { create(:leave_application, :personal, user: user, start_time: start_time, end_time: end_time) }
context 'different expiration date' do
let!(:nearly_expired_leave_time) { create(:leave_time, :annual, user: user, quota: 50, usable_hours: 50, effective_date: effective_date, expiration_date: nearly_expired_date) }
let!(:leave_time) { create(:leave_time, :annual, user: user, quota: 50, usable_hours: 50, effective_date: effective_date, expiration_date: expiration_date) }
it 'should use LeaveTime where nearly to expired prior to other LeaveTimes' do
+ work_periods_by_date = Daikichi::Config::Biz.periods.after(subject.start_time).timeline.until(subject.end_time).to_a.group_by { |wp| wp.start_time.localtime.to_date }.count
expect(subject.errors).to be_empty
- expect(subject.leave_time_usages.size).to be 2
+ expect(subject.leave_time_usages.size).to be work_periods_by_date + 1
nearly_expired_leave_time.reload
leave_time.reload
expect(nearly_expired_leave_time.usable_hours).to be_zero
@@ -125,8 +129,9 @@
let!(:less_usable_hours_leave_time) { create(:leave_time, :annual, user: user, quota: 50, usable_hours: 49, locked_hours: 1, effective_date: effective_date, expiration_date: expiration_date) }
let!(:leave_time) { create(:leave_time, :annual, user: user, quota: 50, usable_hours: 50, effective_date: effective_date, expiration_date: expiration_date) }
it 'should use LeaveTime where less usable_hours prior to other LeaveTimes' do
+ work_periods_by_date = Daikichi::Config::Biz.periods.after(subject.start_time).timeline.until(subject.end_time).to_a.group_by { |wp| wp.start_time.localtime.to_date }.count
expect(subject.errors).to be_empty
- expect(subject.leave_time_usages.size).to be 2
+ expect(subject.leave_time_usages.size).to be work_periods_by_date + 1
less_usable_hours_leave_time.reload
leave_time.reload
expect(less_usable_hours_leave_time.usable_hours).to be_zero
@@ -140,8 +145,9 @@
let!(:nearly_expired_leave_time) { create(:leave_time, :annual, user: user, quota: 50, usable_hours: 50, effective_date: effective_date, expiration_date: nearly_expired_date) }
let!(:less_usable_hours_leave_time) { create(:leave_time, :annual, user: user, quota: 50, usable_hours: 49, locked_hours: 1, effective_date: effective_date, expiration_date: expiration_date) }
it 'should use LeaveTime where nearly to expired prior to other LeaveTime with less usable_hours' do
+ work_periods_by_date = Daikichi::Config::Biz.periods.after(subject.start_time).timeline.until(subject.end_time).to_a.group_by { |wp| wp.start_time.localtime.to_date }.count
expect(subject.errors).to be_empty
- expect(subject.leave_time_usages.size).to be 2
+ expect(subject.leave_time_usages.size).to be work_periods_by_date + 1
nearly_expired_leave_time.reload
less_usable_hours_leave_time.reload
expect(nearly_expired_leave_time.usable_hours).to be_zero
@@ -151,45 +157,49 @@
end
end
- context 'leave_type :sick' do
- let!(:fullpaid_sick) { create(:leave_time, :fullpaid_sick, user: user, quota: 50, usable_hours: 50, effective_date: effective_date, expiration_date: expiration_date) }
- subject { create(:leave_application, :sick, user: user, start_time: start_time, end_time: end_time) }
- it 'should use fullpaid_sick prior to halfpaid_sick' do
- halfpaid_sick = create(:leave_time, :halfpaid_sick, user: user, quota: 50, usable_hours: 50, effective_date: effective_date, expiration_date: expiration_date)
- expect(subject.errors).to be_empty
- expect(subject.leave_time_usages.size).to eq 2
- fullpaid_sick.reload
- halfpaid_sick.reload
- expect(fullpaid_sick.usable_hours).to be_zero
- expect(fullpaid_sick.locked_hours).to be 50
- expect(halfpaid_sick.usable_hours).to be 41
- expect(halfpaid_sick.locked_hours).to be 9
- end
-
- it 'should use fullpaid_sick prior to nearly expired halfpaid_sick' do
- nearly_expired_halfpaid_sick = create(:leave_time, :halfpaid_sick, user: user, quota: 50, usable_hours: 50, effective_date: effective_date, expiration_date: nearly_expired_date)
- expect(subject.errors).to be_empty
- expect(subject.leave_time_usages.size).to be 2
- fullpaid_sick.reload
- nearly_expired_halfpaid_sick.reload
- expect(fullpaid_sick.usable_hours).to be_zero
- expect(fullpaid_sick.locked_hours).to be 50
- expect(nearly_expired_halfpaid_sick.usable_hours).to be 41
- expect(nearly_expired_halfpaid_sick.locked_hours).to be 9
- end
-
- it 'should use fullpaid_sick prior to less usable_hours halfpaid_sick' do
- less_usable_hours_halfpaid_sick = create(:leave_time, :halfpaid_sick, user: user, quota: 50, usable_hours: 49, locked_hours: 1, effective_date: effective_date, expiration_date: expiration_date)
- expect(subject.errors).to be_empty
- expect(subject.leave_time_usages.size).to be 2
- fullpaid_sick.reload
- less_usable_hours_halfpaid_sick.reload
- expect(fullpaid_sick.usable_hours).to be_zero
- expect(fullpaid_sick.locked_hours).to be 50
- expect(less_usable_hours_halfpaid_sick.usable_hours).to be 40
- expect(less_usable_hours_halfpaid_sick.locked_hours).to be 10
- end
- end
+ #TODO: add spec about an application which is used two or more leave_times.
+ #context 'leave_type :sick' do
+ # let!(:fullpaid_sick) { create(:leave_time, :fullpaid_sick, user: user, quota: 50, usable_hours: 50, effective_date: effective_date, expiration_date: expiration_date) }
+ # subject { create(:leave_application, :sick, user: user, start_time: start_time, end_time: end_time) }
+ # it 'should use fullpaid_sick prior to halfpaid_sick' do
+ # halfpaid_sick = create(:leave_time, :halfpaid_sick, user: user, quota: 50, usable_hours: 50, effective_date: effective_date, expiration_date: expiration_date)
+ # expect(subject.errors).to be_empty
+ # work_periods_by_date = Daikichi::Config::Biz.periods.after(subject.start_time).timeline.until(subject.end_time).to_a.group_by { |wp| wp.start_time.localtime.to_date }.count
+ # expect(subject.leave_time_usages.size).to eq work_periods_by_date + 1
+ # fullpaid_sick.reload
+ # halfpaid_sick.reload
+ # expect(fullpaid_sick.usable_hours).to be_zero
+ # expect(fullpaid_sick.locked_hours).to be 50
+ # expect(halfpaid_sick.usable_hours).to be 41
+ # expect(halfpaid_sick.locked_hours).to be 9
+ # end
+
+ # it 'should use fullpaid_sick prior to nearly expired halfpaid_sick' do
+ # nearly_expired_halfpaid_sick = create(:leave_time, :halfpaid_sick, user: user, quota: 50, usable_hours: 50, effective_date: effective_date, expiration_date: nearly_expired_date)
+ # expect(subject.errors).to be_empty
+ # work_periods_by_date = Daikichi::Config::Biz.periods.after(subject.start_time).timeline.until(subject.end_time).to_a.group_by { |wp| wp.start_time.localtime.to_date }.count
+ # expect(subject.leave_time_usages.size).to be work_periods_by_date + 1
+ # fullpaid_sick.reload
+ # nearly_expired_halfpaid_sick.reload
+ # expect(fullpaid_sick.usable_hours).to be_zero
+ # expect(fullpaid_sick.locked_hours).to be 50
+ # expect(nearly_expired_halfpaid_sick.usable_hours).to be 41
+ # expect(nearly_expired_halfpaid_sick.locked_hours).to be 9
+ # end
+
+ # it 'should use fullpaid_sick prior to less usable_hours halfpaid_sick' do
+ # less_usable_hours_halfpaid_sick = create(:leave_time, :halfpaid_sick, user: user, quota: 50, usable_hours: 49, locked_hours: 1, effective_date: effective_date, expiration_date: expiration_date)
+ # expect(subject.errors).to be_empty
+ # work_periods_by_date = Daikichi::Config::Biz.periods.after(subject.start_time).timeline.until(subject.end_time).to_a.group_by { |wp| wp.start_time.localtime.to_date }.count
+ # expect(subject.leave_time_usages.size).to be work_periods_by_date + 1
+ # fullpaid_sick.reload
+ # less_usable_hours_halfpaid_sick.reload
+ # expect(fullpaid_sick.usable_hours).to be_zero
+ # expect(fullpaid_sick.locked_hours).to be 50
+ # expect(less_usable_hours_halfpaid_sick.usable_hours).to be 40
+ # expect(less_usable_hours_halfpaid_sick.locked_hours).to be 10
+ # end
+ #end
end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 98e07898..21301724 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'aasm/rspec'
require 'simplecov'
+require 'capybara/rspec'
SimpleCov.start
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.