]> wagnertech.de Git - mfinanz.git/blob - SL/Presenter/Chart.pm
restart apache2 in postinst
[mfinanz.git] / SL / Presenter / Chart.pm
1 package SL::Presenter::Chart;
2
3 use strict;
4
5 use SL::DB::Chart;
6
7 use Exporter qw(import);
8 our @EXPORT_OK = qw(chart_picker chart);
9
10 use Carp;
11 use Data::Dumper;
12 use SL::Presenter::EscapedText qw(escape is_escaped);
13 use SL::Presenter::Tag qw(input_tag name_to_id html_tag link_tag);
14
15 sub chart {
16   my ($chart, %params) = @_;
17
18   $params{display} ||= 'inline';
19
20   croak "Unknown display type '$params{display}'" unless $params{display} =~ m/^(?:inline|table-cell)$/;
21
22   my $text = escape($chart->accno);
23   if (! delete $params{no_link}) {
24     my $href = 'am.pl?action=edit_account&id=' . escape($chart->id);
25     $text = link_tag($href, $text, %params);
26   }
27   is_escaped($text);
28 }
29
30 sub chart_picker {
31   my ($name, $value, %params) = @_;
32   $value = SL::DB::Manager::Chart->find_by(id => $value) if $value && !ref $value;
33   my $id = delete($params{id}) || name_to_id($name);
34   my $fat_set_item = delete $params{fat_set_item};
35
36   my @classes = $params{class} ? ($params{class}) : ();
37   push @classes, 'chart_autocomplete';
38   push @classes, 'chartpicker_fat_set_item' if $fat_set_item;
39
40   # If there is no 'onClick' parameter, set it to 'this.select()',
41   # so that the user can type directly in the input field
42   # to search another chart.
43   if (!grep { m{onclick}i } keys %params) {
44     $params{onClick} = 'this.select()';
45   }
46
47   my $ret =
48     input_tag($name, (ref $value && $value->can('id') ? $value->id : ''), class => "@classes", type => 'hidden', id => $id) .
49     join('', map { $params{$_} ? input_tag("", delete $params{$_}, id => "${id}_${_}", type => 'hidden') : '' } qw(type category choose booked status)) .
50     input_tag("", (ref $value && $value->can('displayable_name')) ? $value->displayable_name : '', id => "${id}_name", %params);
51
52   $::request->layout->add_javascripts('autocomplete_chart.js');
53   $::request->presenter->need_reinit_widgets($id);
54
55   html_tag('span', $ret, class => 'chart_picker');
56 }
57
58 sub picker { goto &chart_picker }
59
60 1;
61
62 __END__
63
64 =encoding utf-8
65
66 =head1 NAME
67
68 SL::Presenter::Chart - Chart related presenter stuff
69
70 =head1 SYNOPSIS
71
72   # Create an html link for editing/opening a chart
73   my $object = SL::DB::Manager::Chart->get_first;
74   my $html   = SL::Presenter::Chart::chart($object, display => 'inline');
75
76 see also L<SL::Presenter>
77
78 =head1 DESCRIPTION
79
80 see L<SL::Presenter>
81
82 =head1 FUNCTIONS
83
84 =over 2
85
86 =item C<chart, $object, %params>
87
88 Returns a rendered version (actually an instance of
89 L<SL::Presenter::EscapedText>) of the chart object C<$object>
90
91 Remaining C<%params> are passed to the function
92 C<SL::Presenter::Tag::link_tag>. It can include:
93
94 =over 2
95
96 =item * display
97
98 Either C<inline> (the default) or C<table-cell>. Is passed to the function
99 C<SL::Presenter::Tag::link_tag>.
100
101 =item * no_link
102
103 If falsish (the default) then the account number will be linked to the "edit"
104 dialog.
105
106 =back
107
108 =back
109
110 =over 2
111
112 =item C<chart_picker $name, $value, %params>
113
114 All-in-one picker widget for charts. The code was originally copied and adapted
115 from the part picker. The name will be both id and name of the resulting hidden
116 C<id> input field (but the ID can be overwritten with C<$params{id}>).
117
118 An additional dummy input will be generated which is used to find
119 chart. For a detailed description of its behaviour, see section
120 C<CHART PICKER SPECIFICATION>.
121
122 For some examples of usage see the test page at controller.pl?action=Chart/test_page
123
124 C<$value> can be a chart id or a C<Rose::DB:Object> instance.
125
126 C<%params> can include:
127
128 =over 4
129
130 =item * category
131
132 If C<%params> contains C<category> only charts of this category will be
133 available for selection (in the autocompletion and in the popup).
134
135 You may comma separate multiple categories, e.g C<A,Q,L>.
136
137 In SL::DB::Manager::Chart there is also a filter called C<selected_category>,
138 which filters the possible charts according to the category checkboxes the user
139 selects in the popup window. This filter may further restrict the results of
140 the filter category, but the user is not able to "break out of" the limits
141 defined by C<category>. In fact if the categories are restricted by C<category>
142 the popup template should only show checkboxes for those categories.
143
144 =item * type
145
146 If C<%params> contains C<type> only charts of this type will be used for
147 autocompletion, i.e. the selection is filtered. You may comma separate multiple
148 types.
149
150 Type is usually a filter for link: C<AR,AR_paid>
151
152 Type can also be a specially defined type: C<guv>, C<balance>, C<bank>
153
154 See the type filter in SL::DB::Manager::Chart.
155
156 =item * choose
157
158 If C<%params> is passed with choose=1 the input of the filter field in the
159 popup window is cleared. This is useful if a chart was already selected and we
160 want to choose a new chart and immediately see all options.
161
162 =item * fat_set_item
163
164 If C<%params> is passed with fat_set_item=1 the contents of the selected chart
165 object (the elements of the database chart table) are passed back via JSON into
166 the item object. There is an example on the test page.
167
168 Without fat_set_item only the variables id and name (displayable name) are
169 available.
170
171 =item * status
172
173 If C<%params> contains C<status> only charts of this status will be used
174 for autocompletion. C<status> can be one of the following strings:
175 C<valid>, C<invalid> or C<all>. C<valid> is the default if C<status> is
176 not given.
177
178 =back
179
180 C<chart_picker> will register its javascript for inclusion in the next header
181 rendering. If you write a standard controller that only calls C<render> once, it
182 will just work.  In case the header is generated in a different render call
183 (multiple blocks, ajax, old C<bin/mozilla> style controllers) you need to
184 include C<js/autocomplete_chart.js> yourself.
185
186 =back
187
188 =head1 POPUP LAYER
189
190 For users that don't regularly do bookkeeping and haven't memorised all the
191 account numbers and names there are some filter options inside the popup window
192 to quickly narrow down the possible matches. You can filter by
193
194 =over 4
195
196 =item * chart accno or description, inside the input field
197
198 =item * accounts that have already been booked
199
200 =item * by category (AIELQC)
201
202 By selecting category checkboxes the list of available charts can be
203 restricted. If all checkboxes are unchecked all possible charts are shown.
204
205 =back
206
207 There are two views in the list of accounts. By default all possible accounts are shown as a long list.
208
209 But you can also show more information, in this case the resulting list is automatically paginated:
210
211 =over 4
212
213 =item * the balance of the account (as determined by SL::DB::Chart get_balance, which checks for user rights)
214
215 =item * the category
216
217 =item * the invoice date of the last transaction (may lie in the future)
218
219 =back
220
221 The partpicker also has two views, but whereas the compact block view of the
222 partpicker allows part boxes to be aligned in two columns, the chartpicker
223 block view still only shows one chart per row, because there is more
224 information and the account names can be quite long. This behaviour is
225 determined by css, however, and could be changed (div.cpc_block).  The downside
226 of this is that you have to scroll the window to reach the pagination controls.
227
228 The default view of the display logic is to use block view, so we don't have to
229 pass any parameters in the pagination GET. However, the default view for the
230 user is the list view, so the popup window is opened with the "Hide additional
231 information" select box already ticked.
232
233 =head1 CHART PICKER SPECIFICATION
234
235 The following list of design goals were applied:
236
237 =over 4
238
239 =item *
240
241 Charts should not be perceived by the user as distinct inputs of chart number and
242 description but as a single object
243
244 =item *
245
246 Easy to use without documentation for novice users
247
248 =item *
249
250 Fast to use with keyboard for experienced users
251
252 =item *
253
254 Possible to use without any keyboard interaction for mouse (or touchscreen)
255 users
256
257 =item *
258
259 Must not leave the current page in event of ambiguity (cf. current select_item
260 mechanism)
261
262 =item *
263
264 Should not require a feedback/check loop in the common case
265
266 =item *
267
268 Should not be constrained to exact matches
269
270 =back
271
272 The implementation consists of the following parts which will be referenced later:
273
274 =over 4
275
276 =item 1
277
278 A hidden input (id input), used to hold the id of the selected part. The only
279 input that gets submitted
280
281 =item 2
282
283 An input (dummy input) containing a description of the currently selected chart,
284 also used by the user to search for charts
285
286 =item 3
287
288 A jquery.autocomplete mechanism attached to the dummy field
289
290 =item 4
291
292 A popup layer for both feedback and input of additional data in case of
293 ambiguity.
294
295 =item 5
296
297 An internal status of the chart picker, indicating whether id input and dummy
298 input are consistent. After leaving the dummy input the chart picker must
299 place itself in a consistent status.
300
301 =item 6
302
303 A clickable icon (popup trigger) attached to the dummy input, which triggers the popup layer.
304
305 =back
306
307 =head1 BUGS
308
309 None atm :)
310
311 =head1 AUTHOR
312
313 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
314
315 G. Richardson E<lt>information@kivitendo-premium.deE<gt>
316
317 =cut