TopQuickSearch: Auftrag, Angebot, Lieferauftrag, Preisanfrage
[kivitendo-erp.git] / SL / Controller / TopQuickSearch.pm
1 package SL::Controller::TopQuickSearch;
2
3 use strict;
4 use parent qw(SL::Controller::Base);
5
6 use SL::ClientJS;
7 use SL::JSON;
8 use SL::Locale::String qw(t8);
9
10 use Rose::Object::MakeMethods::Generic (
11  'scalar --get_set_init' => [ qw(module js) ],
12 );
13
14 my @available_modules = (
15   'SL::Controller::TopQuickSearch::Article',
16   'SL::Controller::TopQuickSearch::Part',
17   'SL::Controller::TopQuickSearch::Service',
18   'SL::Controller::TopQuickSearch::Assembly',
19   'SL::Controller::TopQuickSearch::Contact',
20   'SL::Controller::TopQuickSearch::SalesQuotation',
21   'SL::Controller::TopQuickSearch::SalesOrder',
22   'SL::Controller::TopQuickSearch::RequestForQuotation',
23   'SL::Controller::TopQuickSearch::PurchaseOrder',
24   'SL::Controller::TopQuickSearch::GLTransaction',
25 );
26 my %modules_by_name;
27
28 sub action_query_autocomplete {
29   my ($self) = @_;
30
31   my $hashes = $self->module->query_autocomplete;
32
33   $self->render(\ SL::JSON::to_json($hashes), { layout => 0, type => 'json', process => 0 });
34 }
35
36 sub action_select_autocomplete {
37   my ($self) = @_;
38
39   my $redirect_url = $self->module->select_autocomplete;
40
41   $self->js->redirect_to($redirect_url)->render;
42 }
43
44 sub action_do_search {
45   my ($self) = @_;
46
47   my $redirect_url = $self->module->do_search;
48
49   if ($redirect_url) {
50     $self->js->redirect_to($redirect_url)
51   }
52
53   $self->js->render;
54 }
55
56 sub available_modules {
57   my ($self) = @_;
58
59   $self->require_modules;
60
61   map { $_->new } @available_modules;
62 }
63
64 sub enabled_modules {
65   my %enabled_names = map {
66     $_ => 1
67   } @{ $::instance_conf->get_quick_search_modules };
68
69   grep {
70     $enabled_names{$_->name}
71   } $_[0]->available_modules
72 }
73
74 sub active_modules {
75   grep {
76     $::auth->assert($_->auth, 1)
77   } $_[0]->enabled_modules
78 }
79
80 sub init_module {
81   my ($self) = @_;
82
83   $self->require_modules;
84
85   die 'Need module' unless $::form->{module};
86
87   die 'Unknown module ' . $::form->{module} unless my $class = $modules_by_name{$::form->{module}};
88
89   $::auth->assert($class->auth);
90
91   return $class->new;
92 }
93
94 sub init_js {
95   SL::ClientJS->new(controller => $_[0])
96 }
97
98 sub require_modules {
99   my ($self) = @_;
100
101   if (!$self->{__modules_required}) {
102     for my $class (@available_modules) {
103       eval "require $class" or die $@;
104       $modules_by_name{ $class->name } = $class;
105     }
106     $self->{__modules_required} = 1;
107   }
108 }
109
110 1;
111
112 __END__
113
114 =encoding utf-8
115
116 =head1 NAME
117
118 SL::Controller::TopQuickSearch - Framework for pluggable quicksearch fields in the layout top header.
119
120 =head1 SYNOPSIS
121
122   use SL::Controller::TopQuickSearch;
123   my $search = SL::Controller::TopQuickSearch->new;
124   $::request->layout->add_javascripts('kivi.QuickSearch.js');
125
126   # in template
127   [%- FOREACH module = search.enabled_modules %]
128   <input type='text' id='top-search-[% module.name %]'>
129   [%- END %]
130
131 =head1 DESCRIPTION
132
133 This controller provides abstraction for different search plugins, and ensures
134 that all follow a common useability scheme.
135
136 Modules should be configurable per user, but currently are not. Disabling
137 modules can be done by removing them from available_modules or in client_config.
138
139 =head1 BEHAVIOUR REQUIREMENTS
140
141 =over 4
142
143 =item *
144
145 A single text input field with the html5 placeholder containing a small
146 description of the target will be rendered from the plugin information.
147
148 =item *
149
150 On typing, the autocompletion must be enabled.
151
152 =item *
153
154 On C<Enter>, the search should redirect to an appropriate listing of matching
155 results.
156
157 If only one item matches the result, the plugin should instead redirect
158 directly to the matched item.
159
160 =item *
161
162 Search terms should accept the broadest possible matching, and if possible with
163 C<multi> parsing.
164
165 =item *
166
167 In case nothing is found, a visual indicator should be given, but no actual
168 redirect should occur.
169
170 =item *
171
172 Each search must check rights and must not present a backdoor into data that
173 the user should not see.
174
175 =item *
176
177 By design the search must not try to guess C<exact matches>.
178
179 =back
180
181 =head1 INTERFACE
182
183 The full interface is described in L<SL::Controller::TopQuickSeach::Base>
184
185 =head1 TODO
186
187   * user configuration
188   * searches for orders, customers, vendors
189
190 =head1 BUGS
191
192 None yet :)
193
194 =head1 AUTHOR
195
196 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
197
198 =cut