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