task-manager 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +4 -0
- data/Rakefile +27 -0
- data/app/assets/images/task-manager/icons/add.png +0 -0
- data/app/assets/images/task-manager/icons/delete.png +0 -0
- data/app/assets/images/task-manager/icons/edit.png +0 -0
- data/app/assets/javascripts/task-manager/application.js +43 -0
- data/app/assets/javascripts/task-manager/extjs/app/controller/Plans.js +359 -0
- data/app/assets/javascripts/task-manager/extjs/app/controller/Tasks.js +56 -0
- data/app/assets/javascripts/task-manager/extjs/app/helper/application_helper.js +24 -0
- data/app/assets/javascripts/task-manager/extjs/app/model/Assignee.js +19 -0
- data/app/assets/javascripts/task-manager/extjs/app/model/Plan.js +195 -0
- data/app/assets/javascripts/task-manager/extjs/app/model/Task.js +23 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Assignees.js +53 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/AssigneesTree.js +3 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Booleans.js +9 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Days.js +38 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Hours.js +31 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Minutes.js +67 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Months.js +19 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Plans.js +6 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/QuarterlyMonths.js +10 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Statuses.js +11 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Tasks.js +6 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Types.js +12 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/WeekDays.js +14 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/AssignablesWindow.js +23 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/Edit.js +189 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/EditWindow.js +21 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/Grid.js +92 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/Index.js +24 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/New.js +190 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/Search.js +132 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/SelectAssignables.js +22 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/SelectAssignablesGrid.js +22 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/SelectAssignablesTree.js +9 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/Window.js +21 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/task/Grid.js +62 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/task/Index.js +21 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/task/Search.js +148 -0
- data/app/assets/javascripts/task-manager/extjs/lib/ux/MultiSelectablePagingGrid.js +20 -0
- data/app/assets/javascripts/task-manager/extjs/lib/ux/RowExpander.js +230 -0
- data/app/assets/stylesheets/task-manager/application.css.scss +13 -0
- data/app/assets/stylesheets/task-manager/extjs.css.scss +43 -0
- data/app/controllers/task_manager/api/v1/plans_controller.rb +251 -0
- data/app/controllers/task_manager/api/v1/tasks_controller.rb +82 -0
- data/app/controllers/task_manager/application_controller.rb +4 -0
- data/app/helpers/task_manager/application_helper.rb +4 -0
- data/app/models/task_manager/assignable.rb +10 -0
- data/app/models/task_manager/callable.rb +10 -0
- data/app/models/task_manager/plan.rb +114 -0
- data/app/models/task_manager/task.rb +81 -0
- data/app/serializers/task_manager/plan_serializer.rb +8 -0
- data/app/serializers/task_manager/task_serializer.rb +8 -0
- data/app/views/layouts/task-manager/application.html.erb +14 -0
- data/config/routes.rb +8 -0
- data/db/migrate/20121102054723_setup_hstore.rb +9 -0
- data/db/migrate/20121102055137_create_task_manager_plans.rb +16 -0
- data/db/migrate/20121102142657_create_task_manager_assignables.rb +13 -0
- data/db/migrate/20121102150720_create_task_manager_callables.rb +13 -0
- data/db/migrate/20121105170602_create_task_manager_tasks.rb +18 -0
- data/lib/task-manager.rb +37 -0
- data/lib/task-manager/api_constraints.rb +12 -0
- data/lib/task-manager/deadline_calculator.rb +22 -0
- data/lib/task-manager/deadline_validator.rb +27 -0
- data/lib/task-manager/engine.rb +5 -0
- data/lib/task-manager/version.rb +3 -0
- data/lib/tasks/task-manager_tasks.rake +4 -0
- metadata +327 -0
@@ -0,0 +1,251 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module TaskManager
|
3
|
+
module Api
|
4
|
+
module V1
|
5
|
+
class PlansController < TaskManager::ApplicationController
|
6
|
+
respond_to :json
|
7
|
+
|
8
|
+
# 查询计划
|
9
|
+
#
|
10
|
+
# 支持的查询属性有:
|
11
|
+
# name 计划名
|
12
|
+
# plan_type 计划类型
|
13
|
+
# autocompletable 是否自动完成
|
14
|
+
# last_task_created_at 最后任务生成时间
|
15
|
+
# enabled_at 生效时间
|
16
|
+
#
|
17
|
+
# 支持的查询操作参见 https://github.com/ernie/ransack/wiki/Basic-Searching
|
18
|
+
#
|
19
|
+
# 分页查询参数:
|
20
|
+
# page 请求的页码,缺省值1
|
21
|
+
# limit 每页记录数,缺省值25
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# # 请求
|
25
|
+
# GET /api/plans?q[name_cont]=... HTTP/1.1
|
26
|
+
# Accept: application/vnd.menglifang.com.cn; version=1
|
27
|
+
#
|
28
|
+
# # 响应
|
29
|
+
# HTTP/1.1 200 OK
|
30
|
+
# {
|
31
|
+
# "total": ...,
|
32
|
+
# "plans": [{
|
33
|
+
# "id": ...,
|
34
|
+
# "name": ...,
|
35
|
+
# "data": ...,
|
36
|
+
# "plan_type": ...,
|
37
|
+
# "enabled_at": ...,
|
38
|
+
# "last_task_created_at": ...,
|
39
|
+
# "begin_to_remind": ...,
|
40
|
+
# "autocompletable": ...,
|
41
|
+
# "created_at": ...,
|
42
|
+
# "updated_at": ...,
|
43
|
+
# "assignees": [{
|
44
|
+
# "id": ...,
|
45
|
+
# "name": ...
|
46
|
+
# }, ...]
|
47
|
+
# }, ...]
|
48
|
+
# }
|
49
|
+
def index
|
50
|
+
plans = TaskManager::Plan.search(params[:q]).result
|
51
|
+
result = {
|
52
|
+
total: plans.count,
|
53
|
+
plans: ActiveModel::ArraySerializer.new(
|
54
|
+
plans.page(params[:page]).per(params[:limit])
|
55
|
+
).as_json
|
56
|
+
}
|
57
|
+
|
58
|
+
render json: result, status: :ok
|
59
|
+
end
|
60
|
+
|
61
|
+
# 创建计划
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# # 请求
|
65
|
+
# POST /api/plans HTTP/1.1
|
66
|
+
# Accept: application/vnd.menglifang.com.cn; version=1
|
67
|
+
#
|
68
|
+
# {
|
69
|
+
# "plan": {
|
70
|
+
# "name": ..., # 必填且唯一
|
71
|
+
# "plan_type": ..., # 必填,有效取值:'daily',
|
72
|
+
# # 'weekly', 'monthly',
|
73
|
+
# # 'quarterly', 'yearly'
|
74
|
+
# "data": {
|
75
|
+
# "x": ..., # 可选
|
76
|
+
# "y": ..., # 可选
|
77
|
+
# "deadline_month": ..., # 当"plan_type"为'yearly'或
|
78
|
+
# # 'quarterly'时,为必填项;
|
79
|
+
# # 否则,为null
|
80
|
+
# "deadline_day": ..., # 当"plan_type"为'monthly'或
|
81
|
+
# # 'weekly'时,为必填项;
|
82
|
+
# # 否则,为null
|
83
|
+
# "deadline_hour": ..., # 必填
|
84
|
+
# "deadline_minute": ... # 必填
|
85
|
+
# },
|
86
|
+
# "enabled_at": ..., # 必填
|
87
|
+
# "begin_to_remind": ..., # 必填且小于等于0
|
88
|
+
# "autocompletable": ..., # 必填,缺省值为false
|
89
|
+
# "assignables_attributes": [{ # 至少需要一个assignable
|
90
|
+
# "assignee_id": ...,
|
91
|
+
# "assignee_type": ...
|
92
|
+
# }, ...],
|
93
|
+
#
|
94
|
+
# "callables_attributes": [{ # 可选
|
95
|
+
# "callback_id": ...,
|
96
|
+
# "callback_type": ...
|
97
|
+
# }]
|
98
|
+
# }
|
99
|
+
# }
|
100
|
+
#
|
101
|
+
# # 响应
|
102
|
+
# ## 成功
|
103
|
+
# HTTP/1.1 201 Created
|
104
|
+
# {
|
105
|
+
# "plan": {
|
106
|
+
# "id": ...,
|
107
|
+
# "name": ...,
|
108
|
+
# "plan_type": ...,
|
109
|
+
# "data": ...,
|
110
|
+
# "enabled_at": ...,
|
111
|
+
# "begin_to_remind": ...,
|
112
|
+
# "autocompletable": ...,
|
113
|
+
# "created_at": ...,
|
114
|
+
# "updated_at": ...,
|
115
|
+
# "assignees": [{
|
116
|
+
# "id": ...,
|
117
|
+
# "name": ...
|
118
|
+
# }, ...]
|
119
|
+
# }
|
120
|
+
# }
|
121
|
+
# ## 失败
|
122
|
+
# HTTP/1.1 422 Unprocessable Entity
|
123
|
+
# {
|
124
|
+
# "errors": {
|
125
|
+
# "name": [...],
|
126
|
+
# ...
|
127
|
+
# }
|
128
|
+
# }
|
129
|
+
def create
|
130
|
+
plan = TaskManager::Plan.new(params[:plan])
|
131
|
+
|
132
|
+
if plan.save
|
133
|
+
render json: plan, status: :created
|
134
|
+
else
|
135
|
+
render json: { errors: plan.errors }, status: :unprocessable_entity
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# 更新计划
|
140
|
+
#
|
141
|
+
# @example
|
142
|
+
# # 请求
|
143
|
+
# PUT /api/plans/... HTTP/1.1
|
144
|
+
# Accept: application/vnd.menglifang.com.cn; version=1
|
145
|
+
#
|
146
|
+
# {
|
147
|
+
# "plan": {
|
148
|
+
# "name": ..., # 必填且唯一
|
149
|
+
# "plan_type": ..., # 必填,有效取值:'daily',
|
150
|
+
# # 'weekly', 'monthly',
|
151
|
+
# # 'quarterly', 'yearly'
|
152
|
+
# "data": {
|
153
|
+
# "x": ..., # 可选
|
154
|
+
# "y": ..., # 可选
|
155
|
+
# "deadline_month": ..., # 当"plan_type"为'yearly'或
|
156
|
+
# # 'quarterly'时,为必填项;
|
157
|
+
# # 否则,为null
|
158
|
+
# "deadline_day": ..., # 当"plan_type"为'monthly'或
|
159
|
+
# # 'weekly'时,为必填项;
|
160
|
+
# # 否则,为null
|
161
|
+
# "deadline_hour": ..., # 必填
|
162
|
+
# "deadline_minute": ... # 必填
|
163
|
+
# },
|
164
|
+
# "enabled_at": ..., # 必填
|
165
|
+
# "begin_to_remind": ..., # 必填且小于等于0
|
166
|
+
# "autocompletable": ..., # 必填,缺省值为false
|
167
|
+
#
|
168
|
+
# "assignables_attributes": [{
|
169
|
+
# "id": ..., ## 可选,
|
170
|
+
# ## 如果有,则更新,否则创建
|
171
|
+
# "assignee_id": ..., ## 必填
|
172
|
+
# "assignee_type": ..., ## 必填
|
173
|
+
# "_destroy": "1" ## 可选,
|
174
|
+
# ## 如果设置,存在则删除,
|
175
|
+
# ## 不存在则忽略
|
176
|
+
# }, ...],
|
177
|
+
#
|
178
|
+
# "callables_attributes": [{ # 可选
|
179
|
+
# "id": ..., ## 可选,
|
180
|
+
# ## 如果有,则更新,否则创建
|
181
|
+
# "callback_id": ..., ## 必填
|
182
|
+
# "callback_type": ..., ## 必填
|
183
|
+
# "_destroy": "1" ## 可选,
|
184
|
+
# ## 如果设置,存在则删除,
|
185
|
+
# ## 不存在则忽略
|
186
|
+
# }]
|
187
|
+
# }
|
188
|
+
# }
|
189
|
+
#
|
190
|
+
# # 响应
|
191
|
+
# ## 成功
|
192
|
+
# HTTP/1.1 202 Accepted
|
193
|
+
# {
|
194
|
+
# "plan": {
|
195
|
+
# "id": ...,
|
196
|
+
# "name": ...,
|
197
|
+
# "plan_type": ...,
|
198
|
+
# "data": ...,
|
199
|
+
# "enabled_at": ...,
|
200
|
+
# "begin_to_remind": ...,
|
201
|
+
# "autocompletable": ...,
|
202
|
+
# "created_at": ...,
|
203
|
+
# "updated_at": ...,
|
204
|
+
# "assignees": [{
|
205
|
+
# "id": ...,
|
206
|
+
# "name": ...
|
207
|
+
# }, ...]
|
208
|
+
# }
|
209
|
+
# }
|
210
|
+
# ## 失败
|
211
|
+
# HTTP/1.1 422 Unprocessable Entity
|
212
|
+
# {
|
213
|
+
# "errors": {
|
214
|
+
# "name": [...],
|
215
|
+
# ...
|
216
|
+
# }
|
217
|
+
# }
|
218
|
+
def update
|
219
|
+
plan.assignables.destroy_all
|
220
|
+
|
221
|
+
if plan.update_attributes(params[:plan])
|
222
|
+
render json: plan, status: :ok
|
223
|
+
else
|
224
|
+
render json: { errors: plan.errors }, status: :unprocessable_entity
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# 删除计划
|
229
|
+
#
|
230
|
+
# @example
|
231
|
+
# # 请求
|
232
|
+
# DELETE /api/plans/... HTTP/1.1
|
233
|
+
# Accept: application/vnd.menglifang.com.cn; version=1
|
234
|
+
#
|
235
|
+
# # 响应
|
236
|
+
# ## 成功
|
237
|
+
# HTTP/1.1 204 No Content
|
238
|
+
def destroy
|
239
|
+
plan.destroy
|
240
|
+
|
241
|
+
head :no_content
|
242
|
+
end
|
243
|
+
|
244
|
+
private
|
245
|
+
def plan
|
246
|
+
TaskManager::Plan.find(params[:id])
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module TaskManager
|
3
|
+
module Api
|
4
|
+
module V1
|
5
|
+
class TasksController < TaskManager::ApplicationController
|
6
|
+
respond_to :json
|
7
|
+
|
8
|
+
# 查询任务
|
9
|
+
#
|
10
|
+
# 支持的查询属性有:
|
11
|
+
# name 任务名
|
12
|
+
# task_type 任务类型
|
13
|
+
# deadline 截止时间
|
14
|
+
# status 状态
|
15
|
+
# updated_at 完成时间
|
16
|
+
#
|
17
|
+
# 支持的查询操作参见 https://github.com/ernie/ransack/wiki/Basic-Searching
|
18
|
+
#
|
19
|
+
# 分页查询参数:
|
20
|
+
# page 请求的页码,缺省值1
|
21
|
+
# limit 每页记录数,缺省值25
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# # 请求
|
25
|
+
# GET /api/tasks?q[name_cont]=... HTTP/1.1
|
26
|
+
# Accept: application/vnd.menglifang.com.cn; version=1
|
27
|
+
#
|
28
|
+
# # 响应
|
29
|
+
# HTTP/1.1 200 OK
|
30
|
+
# {
|
31
|
+
# "total": ...,
|
32
|
+
# "tasks": [{
|
33
|
+
# "id": ...,
|
34
|
+
# "name": ...,
|
35
|
+
# "data": ...,
|
36
|
+
# "task_type": ...,
|
37
|
+
# "deadline": ...,
|
38
|
+
# "status": ...,
|
39
|
+
# "created_at": ...,
|
40
|
+
# "updated_at": ...,
|
41
|
+
# "assignee": {
|
42
|
+
# "id": ...,
|
43
|
+
# "name": ...
|
44
|
+
# }
|
45
|
+
# }, ...]
|
46
|
+
# }
|
47
|
+
def index
|
48
|
+
tasks = TaskManager::Task.search(params[:q]).result
|
49
|
+
result = {
|
50
|
+
total: tasks.count,
|
51
|
+
tasks: ActiveModel::ArraySerializer.new(
|
52
|
+
tasks.page(params[:page]).per(params[:limit])
|
53
|
+
).as_json
|
54
|
+
}
|
55
|
+
|
56
|
+
render json: result, status: :ok
|
57
|
+
end
|
58
|
+
|
59
|
+
# 删除任务
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# # 请求
|
63
|
+
# DELETE /api/tasks/... HTTP/1.1
|
64
|
+
# Accept: application/vnd.menglifang.com.cn; version=1
|
65
|
+
#
|
66
|
+
# # 响应
|
67
|
+
# ## 成功
|
68
|
+
# HTTP/1.1 204 No Content
|
69
|
+
def destroy
|
70
|
+
task.destroy
|
71
|
+
|
72
|
+
head :no_content
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
def task
|
77
|
+
TaskManager::Task.find(params[:id])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module TaskManager
|
3
|
+
# TODO 验证data的合法性
|
4
|
+
class Plan < ActiveRecord::Base
|
5
|
+
include TaskManager::DeadlineCalculator
|
6
|
+
extend Enumerize
|
7
|
+
|
8
|
+
has_many :assignables, as: :target
|
9
|
+
has_many :callables, as: :target
|
10
|
+
|
11
|
+
enumerize :plan_type, in: [:daily, :weekly, :monthly, :quarterly, :yearly]
|
12
|
+
|
13
|
+
serialize :data, ActiveRecord::Coders::Hstore
|
14
|
+
|
15
|
+
accepts_nested_attributes_for :assignables, :callables
|
16
|
+
|
17
|
+
attr_accessible :autocompletable, :data, :last_task_created_at,
|
18
|
+
:name, :plan_type, :begin_to_remind, :enabled_at,
|
19
|
+
:assignables_attributes, :callables_attributes
|
20
|
+
|
21
|
+
validates_presence_of :name, :plan_type, :begin_to_remind,
|
22
|
+
:enabled_at, :assignables
|
23
|
+
validates_uniqueness_of :name
|
24
|
+
validates_numericality_of :begin_to_remind, greater_than_or_equal_to: 0
|
25
|
+
|
26
|
+
# validate the deadline
|
27
|
+
validates :data, deadline: true
|
28
|
+
|
29
|
+
def assignees
|
30
|
+
assignables.collect(&:assignee)
|
31
|
+
end
|
32
|
+
|
33
|
+
def callbacks
|
34
|
+
callables.collect(&:callback)
|
35
|
+
end
|
36
|
+
|
37
|
+
# 生成计划任务
|
38
|
+
#
|
39
|
+
# 为每一个计划的执行者创建一个计划任务。
|
40
|
+
def generate_tasks
|
41
|
+
now = Time.now
|
42
|
+
default_deadline = case plan_type.to_sym
|
43
|
+
when :daily then now.end_of_day
|
44
|
+
when :weekly then now.end_of_week
|
45
|
+
when :monthly then now.end_of_month
|
46
|
+
when :quarterly then now.end_of_quarter
|
47
|
+
when :yearly then now.end_of_year
|
48
|
+
end
|
49
|
+
|
50
|
+
#reminding_at = default_deadline.ago(-(begin_to_remind * 60))
|
51
|
+
reminding_at = default_deadline.ago(begin_to_remind * 60)
|
52
|
+
status = autocompletable ? :finished : :new
|
53
|
+
finished_at = autocompletable ? Time.now : nil
|
54
|
+
|
55
|
+
tasks = []
|
56
|
+
data.symbolize_keys!
|
57
|
+
|
58
|
+
Plan.transaction do
|
59
|
+
assignables.each do |a|
|
60
|
+
tasks << Task.create! do |t|
|
61
|
+
t.name = name
|
62
|
+
t.data = { x: data[:x], y: data[:y] }
|
63
|
+
t.task_type = plan_type
|
64
|
+
t.deadline = calculate_deadline(plan_type, data)
|
65
|
+
t.reminding_at = reminding_at
|
66
|
+
t.status = status
|
67
|
+
t.finished_at = finished_at
|
68
|
+
t.create_assignable(
|
69
|
+
assignee_id: a.assignee_id,
|
70
|
+
assignee_type: a.assignee_type,
|
71
|
+
)
|
72
|
+
t.callables = callables
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
update_attributes(last_task_created_at: Time.now)
|
78
|
+
|
79
|
+
tasks
|
80
|
+
end
|
81
|
+
|
82
|
+
class << self
|
83
|
+
# 返回所有需要创建新任务的计划
|
84
|
+
#
|
85
|
+
# 判断条件:
|
86
|
+
# 1) `enabled_at`在当前时间之前;
|
87
|
+
# 2) `last_task_created_at`在周期内。
|
88
|
+
# 2.1) 日计划:`Time.now.beginning_of_day <= last_task_created_at <= Time.now.end_of_day`
|
89
|
+
# 2.2) 周计划:`Time.now.beginning_of_week <= last_task_created_at <= Time.now.end_of_week`
|
90
|
+
# 2.3) 月计划:`Time.now.beginning_of_month <= last_task_created_at <= Time.now.end_of_month`
|
91
|
+
# 2.4) 季计划:`Time.now.beginning_of_quarter <= last_task_created_at <= Time.now.end_of_quarter`
|
92
|
+
# 2.5) 年计划:`Time.now.beginning_of_year <= last_task_created_at <= Time.now.end_of_year`
|
93
|
+
def active
|
94
|
+
active_by_type(:daily) | active_by_type(:weekly) |
|
95
|
+
active_by_type(:monthly) | active_by_type(:quarterly) |
|
96
|
+
active_by_type(:yearly)
|
97
|
+
end
|
98
|
+
|
99
|
+
def active_by_type(type)
|
100
|
+
now = Time.now
|
101
|
+
beginning_at = case type.to_sym
|
102
|
+
when :daily then now.beginning_of_day
|
103
|
+
when :weekly then now.beginning_of_week
|
104
|
+
when :monthly then now.beginning_of_month
|
105
|
+
when :quarterly then now.beginning_of_quarter
|
106
|
+
when :yearly then now.beginning_of_year
|
107
|
+
end
|
108
|
+
|
109
|
+
where("plan_type = ? AND last_task_created_at <= ?",
|
110
|
+
type, beginning_at).where("enabled_at <= ?", now)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|