knjtasks 0.0.3
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/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +66 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/files/database_schema.rb +174 -0
- data/lib/knjtasks.rb +172 -0
- data/locales/da_DK/LC_MESSAGES/default.mo +0 -0
- data/locales/da_DK/LC_MESSAGES/default.po +1153 -0
- data/locales/da_DK/title.txt +1 -0
- data/locales/en_GB/title.txt +1 -0
- data/models/class_comment.rb +44 -0
- data/models/class_customer.rb +13 -0
- data/models/class_email_check.rb +7 -0
- data/models/class_project.rb +22 -0
- data/models/class_task.rb +163 -0
- data/models/class_task_assigned_user.rb +62 -0
- data/models/class_task_check.rb +26 -0
- data/models/class_timelog.rb +82 -0
- data/models/class_user.rb +125 -0
- data/models/class_user_project_link.rb +66 -0
- data/models/class_user_rank.rb +3 -0
- data/models/class_user_rank_link.rb +17 -0
- data/models/class_user_task_list_link.rb +17 -0
- data/pages/admin.rhtml +7 -0
- data/pages/comment_edit.rhtml +121 -0
- data/pages/comment_update_id_per_obj.rhtml +41 -0
- data/pages/customer_edit.rhtml +69 -0
- data/pages/customer_search.rhtml +80 -0
- data/pages/customer_show.rhtml +50 -0
- data/pages/frontpage.rhtml +198 -0
- data/pages/project_edit.rhtml +129 -0
- data/pages/project_search.rhtml +82 -0
- data/pages/project_show.rhtml +203 -0
- data/pages/task_check_edit.rhtml +98 -0
- data/pages/task_edit.rhtml +168 -0
- data/pages/task_search.rhtml +131 -0
- data/pages/task_show.rhtml +454 -0
- data/pages/timelog_edit.rhtml +134 -0
- data/pages/timelog_search.rhtml +318 -0
- data/pages/user_edit.rhtml +223 -0
- data/pages/user_login.rhtml +83 -0
- data/pages/user_profile.rhtml +89 -0
- data/pages/user_rank_search.rhtml +95 -0
- data/pages/user_search.rhtml +136 -0
- data/pages/user_show.rhtml +87 -0
- data/pages/workstatus.rhtml +320 -0
- data/scripts/fckeditor_validate_login.rb +23 -0
- data/spec/knjtasks_spec.rb +115 -0
- data/spec/spec_helper.rb +12 -0
- data/threads/thread_mail_task_comments.rb +114 -0
- data/www/api/task.rhtml +9 -0
- data/www/api/user.rhtml +20 -0
- data/www/clean.rhtml +14 -0
- data/www/css/default.css +186 -0
- data/www/gfx/body_bg.jpg +0 -0
- data/www/gfx/button_bg.png +0 -0
- data/www/gfx/main_box_design.png +0 -0
- data/www/gfx/main_box_left.png +0 -0
- data/www/gfx/main_box_right.png +0 -0
- data/www/gfx/main_box_top.png +0 -0
- data/www/gfx/main_box_top_left.png +0 -0
- data/www/gfx/main_box_top_right.png +0 -0
- data/www/index.rhtml +154 -0
- data/www/js/default.js +112 -0
- metadata +208 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
<%
|
2
|
+
task_id = _get["task_id"] if _get["task_id"].to_i > 0
|
3
|
+
|
4
|
+
if _get["choice"] == "dosave"
|
5
|
+
save_hash = {
|
6
|
+
:time => _post["textime"],
|
7
|
+
:time_transport => _post["textimetransport"],
|
8
|
+
:transport_length => _post["textransportlength"],
|
9
|
+
:date => Datet.in(_post["texdate"]),
|
10
|
+
:comment => _post["texcomment"],
|
11
|
+
:task_id => _post["seltask"],
|
12
|
+
:invoiced => Knj::Web.checkval(_post["cheinvoiced"], 1, 0)
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
if _get["timelog_id"].to_i > 0
|
17
|
+
timelog = _ob.get(:Timelog, _get["timelog_id"])
|
18
|
+
task_id = timelog.task.id
|
19
|
+
date_val = Datet.in(timelog[:date]).out(:time => false)
|
20
|
+
time_val = timelog[:time]
|
21
|
+
time_transport_val = timelog[:time_transport]
|
22
|
+
url = "&timelog_id=#{timelog.id}"
|
23
|
+
|
24
|
+
if _get["choice"] == "dosave"
|
25
|
+
timelog.update(save_hash)
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
|
29
|
+
if _get["choice"] == "dodelete"
|
30
|
+
_ob.delete(timelog)
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
else
|
34
|
+
date_val = Datet.new.out(:time => false)
|
35
|
+
time_val = "00:00:00"
|
36
|
+
time_transport_val = "00:00:00"
|
37
|
+
|
38
|
+
if _get["choice"] == "dosave"
|
39
|
+
begin
|
40
|
+
timelog = _ob.add(:Timelog, save_hash)
|
41
|
+
rescue RuntimeError => e
|
42
|
+
puts e.message
|
43
|
+
end
|
44
|
+
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
end
|
48
|
+
%>
|
49
|
+
|
50
|
+
<form method="get" onsubmit="return do_save_timelog();">
|
51
|
+
|
52
|
+
<%=_site.boxt(_("Enter details"))%>
|
53
|
+
<table class="form" id="formtimelogedit">
|
54
|
+
<%
|
55
|
+
opts = _ob.list_optshash(:Task, {:debug => false})
|
56
|
+
raise "Empty opts?" if opts.empty?
|
57
|
+
|
58
|
+
print _hb.inputs({
|
59
|
+
:title => _("Task"),
|
60
|
+
:name => :seltask,
|
61
|
+
:value => task_id,
|
62
|
+
:opts => opts,
|
63
|
+
:descr => _("On which task should this timelog be saved?")
|
64
|
+
},{
|
65
|
+
:title => _("Time"),
|
66
|
+
:name => :textime,
|
67
|
+
:value => time_val,
|
68
|
+
:descr => _("How much time should be logged?")
|
69
|
+
},{
|
70
|
+
:title => _("Time transportation"),
|
71
|
+
:name => :textimetransport,
|
72
|
+
:value => time_transport_val,
|
73
|
+
:descr => _("How much time was used on transportation?")
|
74
|
+
},{
|
75
|
+
:title => _("Transportation length"),
|
76
|
+
:name => :textransportlength,
|
77
|
+
:value => [timelog, :transport_length],
|
78
|
+
:descr => _("How many km was used on transportation?")
|
79
|
+
},{
|
80
|
+
:title => _("Date"),
|
81
|
+
:name => :texdate,
|
82
|
+
:value => date_val,
|
83
|
+
:descr => _("On which date was the time used?")
|
84
|
+
},{
|
85
|
+
:title => _("Invoiced"),
|
86
|
+
:name => :cheinvoiced,
|
87
|
+
:value => [timelog, :invoiced],
|
88
|
+
:descr => _("If this timelog has been invoiced or not.")
|
89
|
+
},{
|
90
|
+
:title => _("Comment"),
|
91
|
+
:name => :texcomment,
|
92
|
+
:value => [timelog, :comment],
|
93
|
+
:type => :textarea,
|
94
|
+
:descr => _("What whas done using the time."),
|
95
|
+
:height => 200
|
96
|
+
})
|
97
|
+
%>
|
98
|
+
<tr>
|
99
|
+
<td colspan="2" class="buttons">
|
100
|
+
<input type="submit" value="<%=_("Save")%>" />
|
101
|
+
</td>
|
102
|
+
</tr>
|
103
|
+
</table>
|
104
|
+
<%=_site.boxb%>
|
105
|
+
|
106
|
+
</form>
|
107
|
+
|
108
|
+
<script type="text/javascript">
|
109
|
+
modal_on_opened(function(){
|
110
|
+
$("#textime").focus();
|
111
|
+
});
|
112
|
+
|
113
|
+
function do_save_timelog(){
|
114
|
+
urlstr = "clean.rhtml?show=timelog_edit&choice=dosave<%=url%>";
|
115
|
+
formdata = forms_inputs_read($("#formtimelogedit"));
|
116
|
+
|
117
|
+
$.ajax({
|
118
|
+
type: "POST",
|
119
|
+
url: urlstr,
|
120
|
+
data: formdata,
|
121
|
+
complete: function(data){
|
122
|
+
if (data.responseText.length > 0){
|
123
|
+
alert(data.responseText);
|
124
|
+
}else{
|
125
|
+
modal_close();
|
126
|
+
events.call("on_timelog_added");
|
127
|
+
events.call("do_timelogs_update");
|
128
|
+
}
|
129
|
+
}
|
130
|
+
});
|
131
|
+
|
132
|
+
return false;
|
133
|
+
}
|
134
|
+
</script>
|
@@ -0,0 +1,318 @@
|
|
1
|
+
<%
|
2
|
+
_hb.alert(_("You do not have permission to view this page.")).back if !_site.has_rank?("admin")
|
3
|
+
|
4
|
+
if _get["choice"] == "dosearch"
|
5
|
+
begin
|
6
|
+
date_from = Datet.in(_get["texdatefrom"])
|
7
|
+
rescue
|
8
|
+
_hb.alert(_("Invalid date-from.")).back
|
9
|
+
end
|
10
|
+
|
11
|
+
begin
|
12
|
+
date_to = Datet.in(_get["texdateto"])
|
13
|
+
rescue
|
14
|
+
_hb.alert(_("Invalid date-to.")).back
|
15
|
+
end
|
16
|
+
else
|
17
|
+
date_from = Datet.new
|
18
|
+
date_from.day = 1
|
19
|
+
|
20
|
+
date_to = Datet.new
|
21
|
+
date_to.day = date_to.days_in_month
|
22
|
+
end
|
23
|
+
|
24
|
+
if _get["choice"] == "domarktimelogsasinvoiced"
|
25
|
+
_post["tlog_ids"].split(";").each do |tlog_id|
|
26
|
+
tlog = _ob.get(:Timelog, tlog_id)
|
27
|
+
tlog[:invoiced] = 1 if !tlog.invoiced?
|
28
|
+
end
|
29
|
+
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
|
33
|
+
print _site.header(_("Timelogs"))
|
34
|
+
%>
|
35
|
+
|
36
|
+
<form method="get" onsubmit="return do_submit_criterias();">
|
37
|
+
<%=Knj::Web.hiddens([{:name => :show, :value => :timelog_search}, {:name => :choice, :value => :dosearch}, {:name => :users, :value => ""}, {:name => :projects, :value => ""}])%>
|
38
|
+
|
39
|
+
<%=_site.boxt(_("Enter criteria"), "400px")%>
|
40
|
+
<table class="form">
|
41
|
+
<%
|
42
|
+
print _hb.inputs({
|
43
|
+
:title => _("Date from"),
|
44
|
+
:name => :texdatefrom,
|
45
|
+
:value => date_from.out(:time => false),
|
46
|
+
:descr => _("If you only want timelogs from a specific date and up.")
|
47
|
+
},{
|
48
|
+
:title => _("Date to"),
|
49
|
+
:name => :texdateto,
|
50
|
+
:value => date_to.out(:time => false),
|
51
|
+
:descr => _("If you only want timelogs up to a specific date.")
|
52
|
+
},{
|
53
|
+
:title => _("Comment"),
|
54
|
+
:name => :texcomment,
|
55
|
+
:value => _get["texcomment"],
|
56
|
+
:descr => _("A part of the comment in the timelog you are looking for.")
|
57
|
+
},{
|
58
|
+
:title => _("Users"),
|
59
|
+
:name => :seluser,
|
60
|
+
:opts => _ob.list_optshash(:User, :list_args => {"orderby" => "name"}),
|
61
|
+
:multiple => true,
|
62
|
+
:size => 5,
|
63
|
+
:values => _get["users"].to_s.split(";").map{|ele| ele.to_i},
|
64
|
+
:descr => _("If you want to find timelogs from specific users.")
|
65
|
+
},{
|
66
|
+
:title => _("Projects"),
|
67
|
+
:name => :selproject,
|
68
|
+
:opts => _ob.list_optshash(:Project, :list_args => {"orderby" => "name"}),
|
69
|
+
:multiple => true,
|
70
|
+
:size => 5,
|
71
|
+
:values => _get["projects"].to_s.split(";").map{|ele| ele.to_i},
|
72
|
+
:descr => _("If you want to find timelogs from specific projects.")
|
73
|
+
},{
|
74
|
+
:title => _("Invoiced"),
|
75
|
+
:name => :selinvoiced,
|
76
|
+
:value => _get["selinvoiced"],
|
77
|
+
:descr => _("If you only want to view invoiced, uninvoiced or all timelogs."),
|
78
|
+
:opts => {
|
79
|
+
"" => _("All"),
|
80
|
+
"1" => _("Only invoiced"),
|
81
|
+
"0" => _("Only un-invoiced")
|
82
|
+
}
|
83
|
+
})
|
84
|
+
%>
|
85
|
+
<tr>
|
86
|
+
<td colspan="2" class="buttons">
|
87
|
+
<input type="submit" value="<%=_("Search")%>" />
|
88
|
+
</td>
|
89
|
+
</tr>
|
90
|
+
</table>
|
91
|
+
<%=_site.boxb%>
|
92
|
+
|
93
|
+
</form>
|
94
|
+
|
95
|
+
<script type="text/javascript">
|
96
|
+
$("#texdatefrom").focus();
|
97
|
+
|
98
|
+
function do_submit_criterias(){
|
99
|
+
$("input[name=users]").val(select_values({sel: $("#seluser"), selected: true, expl: ";"}));
|
100
|
+
$("input[name=projects]").val(select_values({sel: $("#selproject"), selected: true, expl: ";"}));
|
101
|
+
$("#seluser").val(false);
|
102
|
+
return true;
|
103
|
+
}
|
104
|
+
|
105
|
+
function do_mark_invoiced(){
|
106
|
+
tlog_ids = []
|
107
|
+
$("input[type=hidden]", $("#table_customer_message")).each(function(){
|
108
|
+
id = $(this).attr("name").substring(9);
|
109
|
+
tlog_ids.push(id);
|
110
|
+
});
|
111
|
+
|
112
|
+
$.ajax({
|
113
|
+
type: "POST",
|
114
|
+
url: "/clean.rhtml?show=timelog_search&choice=domarktimelogsasinvoiced",
|
115
|
+
data: {tlog_ids: tlog_ids.join(";")},
|
116
|
+
async: true,
|
117
|
+
cache: false,
|
118
|
+
complete: function(data){
|
119
|
+
if (data.responseText.length > 0){
|
120
|
+
alert(data.responseText);
|
121
|
+
}else{
|
122
|
+
alert("<%=_'All timelogs was marked as invoiced.'%>");
|
123
|
+
}
|
124
|
+
}
|
125
|
+
});
|
126
|
+
}
|
127
|
+
</script>
|
128
|
+
|
129
|
+
<%
|
130
|
+
if _get["choice"] == "dosearch"
|
131
|
+
args = {"orderby" => "date"}
|
132
|
+
|
133
|
+
if _get["texdatefrom"].to_s.length > 0
|
134
|
+
args["date_from"] = date_from
|
135
|
+
end
|
136
|
+
|
137
|
+
if _get["texdateto"].to_s.length > 0
|
138
|
+
args["date_to"] = date_to
|
139
|
+
end
|
140
|
+
|
141
|
+
if _get["texcomment"].to_s.length > 0
|
142
|
+
args["comment_search"] = _get["texcomment"]
|
143
|
+
end
|
144
|
+
|
145
|
+
if _get["users"].to_s.length > 0
|
146
|
+
args["user_id"] = _get["users"].to_s.split(";")
|
147
|
+
end
|
148
|
+
|
149
|
+
if _get["projects"].to_s.length > 0
|
150
|
+
args["project_id"] = _get["projects"].to_s.split(";")
|
151
|
+
end
|
152
|
+
|
153
|
+
if _get["selinvoiced"].to_s == "1" or _get["selinvoiced"].to_s == "0"
|
154
|
+
args["invoiced"] = _get["selinvoiced"].to_s
|
155
|
+
end
|
156
|
+
|
157
|
+
args_count = args.merge(:count => true)
|
158
|
+
|
159
|
+
tlogs = _ob.list(:Timelog, args)
|
160
|
+
tlogs_count = _ob.list(:Timelog, args_count)
|
161
|
+
|
162
|
+
%>
|
163
|
+
<br />
|
164
|
+
|
165
|
+
<%=_site.boxt(_("Sum"), "350px")%>
|
166
|
+
<table class="form">
|
167
|
+
<%
|
168
|
+
print _hb.inputs({
|
169
|
+
:title => _("Total hours"),
|
170
|
+
:type => :info,
|
171
|
+
:value => Knj::Locales.number_out(tlogs_count[:sum_time].to_f / 3600, 1) + " / " + Knj::Locales.number_out(tlogs_count[:sum_time_transport].to_f / 3600, 1),
|
172
|
+
:descr => _("The total amount of hours of all the found time-logs (first hours used then time used on transport).")
|
173
|
+
},{
|
174
|
+
:title => _("Total transport"),
|
175
|
+
:type => :info,
|
176
|
+
:value => Knj::Locales.number_out(tlogs_count[:sum_transport_length], 1),
|
177
|
+
:descr => _("Total km's of transport used in all the timelogs found.")
|
178
|
+
})
|
179
|
+
%>
|
180
|
+
</table>
|
181
|
+
<%=_site.boxb%>
|
182
|
+
|
183
|
+
<br />
|
184
|
+
|
185
|
+
<%=_site.boxt(_("Results"))%>
|
186
|
+
<table class="form">
|
187
|
+
<thead>
|
188
|
+
<tr>
|
189
|
+
<th><%=_"Timelog"%></th>
|
190
|
+
<th><%=_"User"%></th>
|
191
|
+
<th><%=_"Date"%></th>
|
192
|
+
<th><%=_"Task"%></th>
|
193
|
+
<th><%=_"Invoiced"%></th>
|
194
|
+
<th><%=_"Time"%> / <%=_"Transport"%></th>
|
195
|
+
<th><%=_"Transport length"%></th>
|
196
|
+
</tr>
|
197
|
+
</thead>
|
198
|
+
<tbody>
|
199
|
+
<%
|
200
|
+
tlogs_sorted = {}
|
201
|
+
tlogs.each do |tlog|
|
202
|
+
dbt = Knj::Db::Dbtime.new(tlog[:time])
|
203
|
+
dbt_transport = Knj::Db::Dbtime.new(tlog[:time_transport])
|
204
|
+
tlogs_sorted[tlog[:task_id]] = [] if !tlogs_sorted.has_key?(tlog[:task_id])
|
205
|
+
tlogs_sorted[tlog[:task_id]] << tlog
|
206
|
+
|
207
|
+
%>
|
208
|
+
<tr>
|
209
|
+
<td>
|
210
|
+
<%=tlog.html%>
|
211
|
+
</td>
|
212
|
+
<td>
|
213
|
+
<%=tlog.user_html%>
|
214
|
+
</td>
|
215
|
+
<td>
|
216
|
+
<%=tlog.date_str(:time => false)%>
|
217
|
+
</td>
|
218
|
+
<td>
|
219
|
+
<%=tlog.task_html%>
|
220
|
+
</td>
|
221
|
+
<td>
|
222
|
+
<%=Knj::Strings.yn_str(tlog.invoiced?, _("Yes"), _("No"))%>
|
223
|
+
</td>
|
224
|
+
<td>
|
225
|
+
<%=Knj::Locales.number_out(dbt.hours_total, 1)%> / <%=Knj::Locales.number_out(dbt_transport.hours_total, 1)%>
|
226
|
+
</td>
|
227
|
+
<td>
|
228
|
+
<%=Knj::Locales.number_out(tlog[:transport_length], 0)%>
|
229
|
+
</td>
|
230
|
+
</tr>
|
231
|
+
<%
|
232
|
+
end
|
233
|
+
|
234
|
+
if tlogs.empty?
|
235
|
+
%>
|
236
|
+
<tr>
|
237
|
+
<td colspan="1" class="error">
|
238
|
+
<%=_("No timelogs were found.")%>
|
239
|
+
</td>
|
240
|
+
</tr>
|
241
|
+
<%
|
242
|
+
end
|
243
|
+
%>
|
244
|
+
</tbody>
|
245
|
+
</table>
|
246
|
+
<%=_site.boxb%>
|
247
|
+
|
248
|
+
<br />
|
249
|
+
|
250
|
+
<%=_site.boxt(_("Customer message"))%>
|
251
|
+
<table class="list" id="table_customer_message">
|
252
|
+
<thead>
|
253
|
+
<tr>
|
254
|
+
<th><%=_"Date"%>/<%=_"Hours"%></th>
|
255
|
+
<th><%=_"User"%></th>
|
256
|
+
<th><%=_"Description"%></th>
|
257
|
+
</tr>
|
258
|
+
</thead>
|
259
|
+
<tbody>
|
260
|
+
<%
|
261
|
+
tlogs_sorted.each do |task_id, tlogs_arr|
|
262
|
+
task = _ob.get(:Task, task_id)
|
263
|
+
|
264
|
+
%>
|
265
|
+
<tr>
|
266
|
+
<td colspan="3" class="tdt" style="padding-top: 10px;">
|
267
|
+
<%=task.name.html%>
|
268
|
+
</td>
|
269
|
+
</tr>
|
270
|
+
<%
|
271
|
+
|
272
|
+
first = true
|
273
|
+
tlogs_arr.each do |tlog|
|
274
|
+
if !first
|
275
|
+
%>
|
276
|
+
<tr>
|
277
|
+
<td colspan="3"><hr size="1" color="#cfcfcf" /></td>
|
278
|
+
</tr>
|
279
|
+
<%
|
280
|
+
end
|
281
|
+
|
282
|
+
first = false if first
|
283
|
+
|
284
|
+
%>
|
285
|
+
<tr>
|
286
|
+
<td style="text-align: center;">
|
287
|
+
<input type="hidden" name="timelogs_<%=tlog.id%>" value="1" />
|
288
|
+
|
289
|
+
<%=tlog.date_str(:time => false)%><br />
|
290
|
+
<%=Knj::Locales.number_out(tlog.time_dbt.hours_total, 2)%> / <%=Knj::Locales.number_out(tlog.time_transport_dbt.hours_total, 2)%>
|
291
|
+
</td>
|
292
|
+
<td class="nowrap">
|
293
|
+
<%=tlog.user.name.html%>
|
294
|
+
</td>
|
295
|
+
<td>
|
296
|
+
<%=tlog.comment_html%>
|
297
|
+
</td>
|
298
|
+
</tr>
|
299
|
+
<%
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
if !tlogs_sorted.empty?
|
304
|
+
%>
|
305
|
+
<tr>
|
306
|
+
<td colspan="3" style="padding-top: 15px; text-align: right;">
|
307
|
+
<input type="button" value="<%=_"Mark timelogs as invoiced"%>" onclick="if (confirm('<%=_"Are you sure you want to mark all the found timelogs as invoiced?"%>')){do_mark_invoiced();}" />
|
308
|
+
</td>
|
309
|
+
</tr>
|
310
|
+
<%
|
311
|
+
end
|
312
|
+
%>
|
313
|
+
</tbody>
|
314
|
+
</table>
|
315
|
+
<%=_site.boxb%>
|
316
|
+
<%
|
317
|
+
end
|
318
|
+
%>
|