syc-task 0.0.7 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +159 -15
- data/bin/console_timer +75 -0
- data/bin/syctask +246 -68
- data/lib/syctask.rb +4 -1
- data/lib/syctask/environment.rb +427 -2
- data/lib/syctask/schedule.rb +84 -21
- data/lib/syctask/settings.rb +43 -0
- data/lib/syctask/statistics.rb +196 -0
- data/lib/syctask/task.rb +58 -2
- data/lib/syctask/task_planner.rb +94 -13
- data/lib/syctask/task_scheduler.rb +5 -1
- data/lib/syctask/task_service.rb +55 -15
- data/lib/syctask/task_tracker.rb +27 -17
- data/lib/syctask/times.rb +29 -0
- data/lib/syctask/version.rb +1 -1
- data/lib/syctime/time_util.rb +46 -7
- data/lib/sycutil/console_timer.rb +75 -0
- metadata +215 -136
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require_relative 'environment.rb'
|
3
|
+
|
4
|
+
# Syctask module implements functions for managing tasks
|
5
|
+
module Syctask
|
6
|
+
|
7
|
+
# Creates settings for syctask that are saved to files and retrieved when
|
8
|
+
# syctask is started
|
9
|
+
class Settings
|
10
|
+
|
11
|
+
# Creates general purpose tasks that can be tracked with syctask start. The
|
12
|
+
# general purpose files are saved to a file default_tasks in the syctask
|
13
|
+
# system directory
|
14
|
+
def tasks(tasks)
|
15
|
+
service = Syctask::TaskService.new
|
16
|
+
if File.exists? Syctask::DEFAULT_TASKS
|
17
|
+
general = YAML.load_file(Syctask::DEFAULT_TASKS)
|
18
|
+
else
|
19
|
+
general = {}
|
20
|
+
end
|
21
|
+
tasks.split(',').each do |task|
|
22
|
+
index = general.keys.find_index(task.upcase)
|
23
|
+
general[task.upcase] = service.create(Syctask::SYC_DIR,
|
24
|
+
{},
|
25
|
+
task.upcase) unless index
|
26
|
+
end
|
27
|
+
File.open(Syctask::DEFAULT_TASKS, 'w') {|f| YAML.dump(general, f)}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Retrieves the general purpose files from the default_tasks file in the
|
31
|
+
# syctask system directory
|
32
|
+
def read_tasks
|
33
|
+
if File.exists? Syctask::DEFAULT_TASKS and not \
|
34
|
+
File.read(Syctask::DEFAULT_TASKS).empty?
|
35
|
+
YAML.load_file(Syctask::DEFAULT_TASKS)
|
36
|
+
else
|
37
|
+
{}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'rainbow'
|
2
|
+
require_relative '../syctime/time_util.rb'
|
3
|
+
require_relative 'settings.rb'
|
4
|
+
|
5
|
+
include Syctime
|
6
|
+
|
7
|
+
module Syctask
|
8
|
+
|
9
|
+
# Creates statistics about the work and meeting times as well about the task
|
10
|
+
# processing
|
11
|
+
class Statistics
|
12
|
+
|
13
|
+
# Initializes the Statistics object with the general purpose tassk
|
14
|
+
def initialize
|
15
|
+
settings = Settings::new
|
16
|
+
tasks = settings.read_tasks
|
17
|
+
@general_purpose_tasks = tasks.nil? ? [] : tasks.keys
|
18
|
+
end
|
19
|
+
|
20
|
+
# Creates a statistics report
|
21
|
+
def report(file, from="", to=from)
|
22
|
+
|
23
|
+
from, to, time_log, count_log = logs(file, from, to)
|
24
|
+
working_days = time_log["work"].count.to_s if time_log["work"]
|
25
|
+
working_days ||= "0"
|
26
|
+
value_size = {key: 0, total: 0, min: 0, max: 0, average: 0}
|
27
|
+
report_lines = {}
|
28
|
+
report = sprintf("%s to %s", "#{from.strftime("%Y-%m-%d")}".bright,
|
29
|
+
"#{to.strftime("%Y-%m-%d")}".bright) +
|
30
|
+
sprintf(" (%s working days)\n", working_days.bright) +
|
31
|
+
sprintf("%24s", "Total".bright) +
|
32
|
+
sprintf("%26s", "Min ".bright) +
|
33
|
+
sprintf("%26s", "Max ".bright) +
|
34
|
+
sprintf("%29s", "Average\n".bright)
|
35
|
+
report << sprintf("%s\n", "Time".bright)
|
36
|
+
time_log.each do |key,value|
|
37
|
+
total, min, max, average = stats(value)
|
38
|
+
total = Syctime::separated_time_string(total, ":")
|
39
|
+
min = Syctime::separated_time_string(min, ":")
|
40
|
+
max = Syctime::separated_time_string(max, ":")
|
41
|
+
average = Syctime::separated_time_string(average, ":")
|
42
|
+
set_max_value_sizes(key, total, min, max, average, value_size)
|
43
|
+
report_lines[key] = [total, min, max, average]
|
44
|
+
end
|
45
|
+
|
46
|
+
report << create_report_line_strings(report_lines, value_size)
|
47
|
+
|
48
|
+
report_lines = {}
|
49
|
+
value_size = {key: 0, total: 0, min: 0, max: 0, average: 0}
|
50
|
+
|
51
|
+
report << sprintf("%s\n", "Count".bright)
|
52
|
+
count_log.each do |key,value|
|
53
|
+
total, min, max, average = stats_count(value)
|
54
|
+
set_max_value_sizes(key, total, min, max, average, value_size)
|
55
|
+
report_lines[key] = [total, min, max, average]
|
56
|
+
end
|
57
|
+
|
58
|
+
report << create_report_line_strings(report_lines, value_size)
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
# Creates report line strings
|
63
|
+
def create_report_line_strings(lines, value_size)
|
64
|
+
report = ""
|
65
|
+
lines.each do |key, value|
|
66
|
+
total = value[0]
|
67
|
+
min = value[1]
|
68
|
+
max = value[2]
|
69
|
+
average = value[3]
|
70
|
+
report << report_line(key, total, min, max, average, value_size)
|
71
|
+
end
|
72
|
+
report
|
73
|
+
end
|
74
|
+
|
75
|
+
# Determines the max string size of the values
|
76
|
+
def set_max_value_sizes(key, total, min, max, average, value_size)
|
77
|
+
value_size[:key] = [value_size[:key], key.size].max
|
78
|
+
value_size[:total] = [value_size[:total], total.size].max
|
79
|
+
value_size[:min] = [value_size[:min], min.size].max
|
80
|
+
value_size[:max] = [value_size[:max], max.size].max
|
81
|
+
value_size[:average] = [value_size[:average], average.size].max
|
82
|
+
end
|
83
|
+
|
84
|
+
# Creates a report line for the report
|
85
|
+
def report_line(key, total, min, max, average, sizes={})
|
86
|
+
color = :green if key == 'task'
|
87
|
+
color = :yellow if key == 'unplanned' or @general_purpose_tasks.
|
88
|
+
find_index(key)
|
89
|
+
key = key[0..8]
|
90
|
+
report = sprintf(" %s#{' '*(10-key.size)}", key).color(color)
|
91
|
+
report << sprintf("%#{sizes[:total]}s#{' '*(10-sizes[:total]+8)}", total).
|
92
|
+
color(color)
|
93
|
+
report << sprintf("%#{sizes[:min]}s#{' '*(10-sizes[:min]+8)}", min).
|
94
|
+
color(color)
|
95
|
+
report << sprintf("%#{sizes[:max]}s#{' '*(10-sizes[:max]+8)}", max).
|
96
|
+
color(color)
|
97
|
+
report << sprintf("%#{sizes[:average]}s\n", average).color(color)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Calculates the average of a task processing, work or meeting time
|
101
|
+
def average(data)
|
102
|
+
sum = 0
|
103
|
+
data.each do |d|
|
104
|
+
sum += time_for_string(d[1]) - time_for_string(d[0])
|
105
|
+
end
|
106
|
+
sum / data.size
|
107
|
+
end
|
108
|
+
|
109
|
+
# Calculates the minimum duration of task processing, work or meeting time
|
110
|
+
def min(data)
|
111
|
+
diffs = []
|
112
|
+
data.each do |d|
|
113
|
+
diffs << time_for_string(d[1]) - time_for_string(d[0])
|
114
|
+
end
|
115
|
+
diffs.min
|
116
|
+
end
|
117
|
+
|
118
|
+
# Calculates the maximum duration of task processing, work or meeting time
|
119
|
+
def max(data)
|
120
|
+
diffs = []
|
121
|
+
data.each do |d|
|
122
|
+
diffs << time_for_string(d[1]) - time_for_string(d[0])
|
123
|
+
end
|
124
|
+
diffs.max
|
125
|
+
end
|
126
|
+
|
127
|
+
# Calculates total, min, max and average time of task processing, work or
|
128
|
+
# meeting time
|
129
|
+
def stats(data)
|
130
|
+
diffs = []
|
131
|
+
data.each do |d|
|
132
|
+
diffs << time_for_string(d[1]) - time_for_string(d[0])
|
133
|
+
end
|
134
|
+
[diffs.inject(:+), diffs.min, diffs.max, diffs.inject(:+) / diffs.size]
|
135
|
+
end
|
136
|
+
|
137
|
+
# Calculates the total, min, max and average count of task processing,
|
138
|
+
# creation, update, done, delete
|
139
|
+
def stats_count(data)
|
140
|
+
count = []
|
141
|
+
data.each do |key,value|
|
142
|
+
count << value.to_i
|
143
|
+
end
|
144
|
+
[count.inject(:+), count.min, count.max, count.inject(:+) / count.size]
|
145
|
+
end
|
146
|
+
|
147
|
+
# Retrieves the log entries from the log file
|
148
|
+
def logs(file, from="", to=from)
|
149
|
+
times = []
|
150
|
+
time_data = {}
|
151
|
+
time_types = %w{work meeting task}
|
152
|
+
time_types << @general_purpose_tasks
|
153
|
+
time_types.flatten!
|
154
|
+
count_data = {}
|
155
|
+
count_types = %w{meeting task create done update delete}
|
156
|
+
count_types << @general_purpose_tasks
|
157
|
+
count_types.flatten!
|
158
|
+
IO.readlines(file).each do |line|
|
159
|
+
values = line.split(";")
|
160
|
+
time = time_for_string(values[4])
|
161
|
+
times << time
|
162
|
+
next if values[0] == "start"
|
163
|
+
unless from == ""
|
164
|
+
next unless Syctime::date_between?(time, from, to)
|
165
|
+
end
|
166
|
+
values[0] = values[3] if @general_purpose_tasks.find_index(values[3])
|
167
|
+
values[0] = "task" if values[0] == "stop"
|
168
|
+
if count_types.find_index(values[0])
|
169
|
+
time = time.strftime("%Y-%m-%d")
|
170
|
+
count_data[values[0]] = {} unless count_data[values[0]]
|
171
|
+
count_data[values[0]][time] = 0 unless count_data[values[0]][time]
|
172
|
+
count_data[values[0]][time] += 1
|
173
|
+
if @general_purpose_tasks.find_index(values[0])
|
174
|
+
count_data['unplanned'] = {} unless count_data['unplanned']
|
175
|
+
count_data['unplanned'][time] = 0 unless \
|
176
|
+
count_data['unplanned'][time]
|
177
|
+
count_data['unplanned'][time] += 1
|
178
|
+
end
|
179
|
+
end
|
180
|
+
if time_types.find_index(values[0])
|
181
|
+
time_data[values[0]] = [] unless time_data[values[0]]
|
182
|
+
time_data[values[0]] << [values[4],values[5]]
|
183
|
+
if @general_purpose_tasks.find_index(values[0])
|
184
|
+
time_data['unplanned'] = [] unless time_data['unplanned']
|
185
|
+
time_data['unplanned'] << [values[4],values[5]]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
from = times.min if from == ""
|
190
|
+
to = times.max if to == ""
|
191
|
+
[from, to, time_data, count_data]
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
data/lib/syctask/task.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'rainbow'
|
3
3
|
require_relative 'evaluator'
|
4
|
+
require_relative 'environment.rb'
|
5
|
+
require_relative 'task_tracker.rb'
|
4
6
|
|
5
7
|
# Syctask provides functions for managing tasks in a task list
|
6
8
|
module Syctask
|
@@ -25,9 +27,11 @@ module Syctask
|
|
25
27
|
# ID of the task
|
26
28
|
attr_reader :id
|
27
29
|
# Duration specifies the planned time for processing the task
|
28
|
-
|
30
|
+
attr_reader :duration
|
31
|
+
# Remaining time is the duration subtracted by the lead time since last plan
|
32
|
+
attr_reader :remaining
|
29
33
|
# Lead time is the time this task has been processed
|
30
|
-
|
34
|
+
attr_reader :lead_time
|
31
35
|
# Creation date
|
32
36
|
attr_reader :creation_date
|
33
37
|
# Update date
|
@@ -45,6 +49,13 @@ module Syctask
|
|
45
49
|
@options = options
|
46
50
|
@options[:note] =
|
47
51
|
"#{@creation_date}\n#{@options[:note]}\n" if @options[:note]
|
52
|
+
if @options[:follow_up] or @options[:due_date]
|
53
|
+
@duration = 2 * 15 * 60
|
54
|
+
@remaining = 2 * 15 * 60
|
55
|
+
else
|
56
|
+
@duration = 0
|
57
|
+
@remaining = 0
|
58
|
+
end
|
48
59
|
@id = id
|
49
60
|
end
|
50
61
|
|
@@ -69,6 +80,11 @@ module Syctask
|
|
69
80
|
# supplemented with the new values and not overridden.
|
70
81
|
def update(options)
|
71
82
|
@update_date = Time.now.strftime("%Y-%m-%d - %H:%M:%S")
|
83
|
+
if options[:duration]
|
84
|
+
set_duration(options.delete(:duration).to_i * 15 * 60)
|
85
|
+
elsif options[:follow_up] or options[:due_date]
|
86
|
+
set_duration(2 * 15 * 60) if @duration.nil?
|
87
|
+
end
|
72
88
|
options.keys.each do |key|
|
73
89
|
new_value = options[key]
|
74
90
|
|
@@ -95,6 +111,28 @@ module Syctask
|
|
95
111
|
!@updated_date.nil?
|
96
112
|
end
|
97
113
|
|
114
|
+
# Sets the duration that this task is planned for processing. Assigns to
|
115
|
+
# remaining the duration time
|
116
|
+
def set_duration(duration)
|
117
|
+
@duration = duration
|
118
|
+
@remaining = duration
|
119
|
+
end
|
120
|
+
|
121
|
+
# Updates the lead time. Adds the lead time to @lead_time and calculates
|
122
|
+
# @remaining
|
123
|
+
def update_lead_time(lead_time)
|
124
|
+
if @lead_time
|
125
|
+
@lead_time += lead_time
|
126
|
+
else
|
127
|
+
@lead_time = lead_time
|
128
|
+
end
|
129
|
+
if @remaining
|
130
|
+
@remaining -= lead_time
|
131
|
+
else
|
132
|
+
@remaining = @duration.to_i - lead_time
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
98
136
|
# Marks the task as done. When done than the done date is set. Optionally a
|
99
137
|
# note can be provided.
|
100
138
|
def done(note="")
|
@@ -102,6 +140,7 @@ module Syctask
|
|
102
140
|
if note
|
103
141
|
options[:note] = "#{@done_date}\n#{note}\n#{@options[:note]}"
|
104
142
|
end
|
143
|
+
Syctask::log_task("done", self)
|
105
144
|
end
|
106
145
|
|
107
146
|
# Checks if this task is done. Returns true if done otherwise false
|
@@ -109,6 +148,23 @@ module Syctask
|
|
109
148
|
!@done_date.nil?
|
110
149
|
end
|
111
150
|
|
151
|
+
# Checks if task is scheduled for today. Returns true if follow up or due
|
152
|
+
# date is today otherwise false.
|
153
|
+
def today?
|
154
|
+
evaluator = Evaluator.new
|
155
|
+
today = Time.now.strftime("%Y-%m-%d")
|
156
|
+
evaluator.compare_dates(@options[:follow_up], today) or \
|
157
|
+
evaluator.compare_dates(@options[:due_date], today)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Checks whether the task is currently tracked. Returns true if so otherwise
|
161
|
+
# false
|
162
|
+
def tracked?
|
163
|
+
tracker = Syctask::TaskTracker.new
|
164
|
+
task = tracker.tracked_task
|
165
|
+
task.nil? ? false : task == self
|
166
|
+
end
|
167
|
+
|
112
168
|
# Compares the provided elements in the filter with the correspondent
|
113
169
|
# elements in the task. When all comparissons match than true is returned.
|
114
170
|
# If one comparisson does not match false is returned. If filter is empty
|
data/lib/syctask/task_planner.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
1
|
require 'fileutils'
|
2
|
+
require 'rainbow'
|
2
3
|
require_relative '../sycutil/console.rb'
|
3
4
|
require_relative 'task_service.rb'
|
5
|
+
require_relative 'environment.rb'
|
4
6
|
|
5
7
|
module Syctask
|
6
8
|
# String that is prompted during planning
|
7
9
|
PROMPT_STRING = '(a)dd, (c)omplete, (s)kip, (q)uit: '
|
10
|
+
# String that is prompted during inspect
|
11
|
+
INSPECT_STRING = '(e)dit, (d)one, de(l)ete, (p)lan, (c)omplete, (s)kip, '+
|
12
|
+
'(q)uit: '
|
8
13
|
# String that is prompted during prioritization
|
9
14
|
PRIORITIZE_STRING = 'Task 1 has (h)igher or (l)ower priority, or (q)uit: '
|
10
15
|
|
@@ -12,7 +17,7 @@ module Syctask
|
|
12
17
|
# be prioritized to determine the most to the least important tasks.
|
13
18
|
class TaskPlanner
|
14
19
|
# The task where the planned tasks are saved to
|
15
|
-
WORK_DIR = File.expand_path("~/.tasks")
|
20
|
+
WORK_DIR = Syctask::SYC_DIR #File.expand_path("~/.tasks")
|
16
21
|
|
17
22
|
# Creates a new TaskPlanner
|
18
23
|
def initialize
|
@@ -41,9 +46,71 @@ module Syctask
|
|
41
46
|
choice = @console.prompt PROMPT_STRING
|
42
47
|
case choice
|
43
48
|
when 'a'
|
44
|
-
|
45
|
-
duration
|
46
|
-
|
49
|
+
duration = 0
|
50
|
+
until duration > 0
|
51
|
+
print "Duration (1 = 15 minutes, RETURN defaults to 30 minutes): "
|
52
|
+
answer = gets.chomp
|
53
|
+
duration = answer.empty? ? 2 : answer.to_i
|
54
|
+
end
|
55
|
+
task.set_duration(units_to_time(duration))
|
56
|
+
task.options[:follow_up] = date
|
57
|
+
@service.save(task.dir, task)
|
58
|
+
planned << task
|
59
|
+
count += 1
|
60
|
+
when 'c'
|
61
|
+
re_display = true
|
62
|
+
redo
|
63
|
+
when 's'
|
64
|
+
#do nothing
|
65
|
+
when 'q'
|
66
|
+
break
|
67
|
+
end
|
68
|
+
end
|
69
|
+
save_tasks(planned)
|
70
|
+
count
|
71
|
+
end
|
72
|
+
|
73
|
+
# Inspect allows to edit, delete and mark tasks as done
|
74
|
+
def inspect_tasks(tasks, date=Time.now.strftime("%Y-%m-%d"))
|
75
|
+
already_planned = self.get_tasks(date)
|
76
|
+
count = 0
|
77
|
+
re_display = false
|
78
|
+
planned = []
|
79
|
+
tasks.each do |task|
|
80
|
+
next if already_planned.find_index {|t| t == task}
|
81
|
+
unless re_display
|
82
|
+
task.print_pretty
|
83
|
+
else
|
84
|
+
task.print_pretty(true)
|
85
|
+
re_display = false
|
86
|
+
end
|
87
|
+
choice = @console.prompt INSPECT_STRING
|
88
|
+
case choice
|
89
|
+
when 'e'
|
90
|
+
task_file = "#{task.dir}/#{task.id}.task"
|
91
|
+
system "vi #{task_file}" if File.exists? task_file
|
92
|
+
redo
|
93
|
+
when 'd'
|
94
|
+
puts "Enter a note or hit <RETURN>"
|
95
|
+
note = gets.chomp
|
96
|
+
task.done(note)
|
97
|
+
@service.save(task.dir, task)
|
98
|
+
STDOUT.puts sprintf("--> Marked task %d as done",
|
99
|
+
task.id).color(:green)
|
100
|
+
when 'l'
|
101
|
+
print "Confirm delete task (Y/n)? "
|
102
|
+
answer = gets.chomp
|
103
|
+
count = @service.delete(task.dir, {id: task.id.to_s}) if answer == "Y"
|
104
|
+
puts sprintf("--> Deleted %d task%s",
|
105
|
+
count, count == 1 ? "" : "s").color(:green)
|
106
|
+
when 'p'
|
107
|
+
duration = 0
|
108
|
+
until duration > 0
|
109
|
+
print "Duration (1 = 15 minutes, RETURN defaults to 30 minutes): "
|
110
|
+
answer = gets.chomp
|
111
|
+
duration = answer.empty? ? 2 : answer.to_i
|
112
|
+
end
|
113
|
+
task.set_duration(units_to_time(duration))
|
47
114
|
task.options[:follow_up] = date
|
48
115
|
@service.save(task.dir, task)
|
49
116
|
planned << task
|
@@ -61,19 +128,25 @@ module Syctask
|
|
61
128
|
count
|
62
129
|
end
|
63
130
|
|
64
|
-
# Order tasks in the provided IDs sequence at the specified date. If not
|
65
|
-
# IDs are provided than rest of tasks is appended to the end of the plan.
|
66
|
-
#
|
67
|
-
|
131
|
+
# Order tasks in the provided IDs sequence at the specified date. If not all
|
132
|
+
# IDs are provided than rest of tasks is appended to the end of the plan. If
|
133
|
+
# a position (last, first and a number) is provided the ordered tasks are
|
134
|
+
# inserted at the specified position. Returns the count of ordered tasks,
|
135
|
+
# the count of the rest of the tasks and the position where the ordered
|
136
|
+
# tasks have been inserted.
|
137
|
+
def order_tasks(date, ids, pos=0)
|
68
138
|
tasks = get_tasks(date)
|
139
|
+
pos = "0" if pos.class == String and pos.downcase == 'first'
|
140
|
+
pos = tasks.size.to_s if pos.class == String and pos.downcase == 'last'
|
69
141
|
ordered = []
|
70
142
|
ids.each do |id|
|
71
143
|
index = tasks.find_index {|t| t.id == id.to_i}
|
72
144
|
ordered << tasks.delete_at(index) if index
|
73
145
|
end
|
74
|
-
|
75
|
-
|
76
|
-
|
146
|
+
pos = [pos.to_i.abs,tasks.size].min
|
147
|
+
tasks.insert(pos, ordered)
|
148
|
+
save_tasks(tasks.flatten!, true)
|
149
|
+
[ordered.size, tasks.size, pos]
|
77
150
|
end
|
78
151
|
|
79
152
|
# Prioritize tasks by pair wise comparisson. Each task is compared to the
|
@@ -119,13 +192,15 @@ module Syctask
|
|
119
192
|
save_tasks(planned, true)
|
120
193
|
end
|
121
194
|
|
122
|
-
# Moves the specified tasks to the specified date.
|
123
|
-
#
|
195
|
+
# Moves the specified tasks to the specified date. Sets the remaining timer
|
196
|
+
# to at least 15 minutes and sets the duration to the remaining timer's
|
197
|
+
# values. Returns the count of moved files
|
124
198
|
def move_tasks(filter={}, from_date=Time.now.strftime("%Y-%m-%d"), to_date)
|
125
199
|
return 0 if from_date == to_date
|
126
200
|
moved = get_tasks(from_date, filter)
|
127
201
|
moved.each do |task|
|
128
202
|
task.options[:follow_up] = to_date
|
203
|
+
task.set_duration([task.remaining, 900].max)
|
129
204
|
@service.save(task.dir, task)
|
130
205
|
end
|
131
206
|
add_tasks(moved, to_date)
|
@@ -170,6 +245,12 @@ module Syctask
|
|
170
245
|
|
171
246
|
private
|
172
247
|
|
248
|
+
# Calculates the time for time units. One time unit equals to 900 seconds or
|
249
|
+
# 15 minutes. The return value is in seconds
|
250
|
+
def units_to_time(units)
|
251
|
+
units * 15 * 60
|
252
|
+
end
|
253
|
+
|
173
254
|
# Creates a file where the planned tasks are saved to
|
174
255
|
def make_todo_today_file(date)
|
175
256
|
file_name = Time.now.strftime("#{date}_planned_tasks")
|