ShippedQty: Algorithmusdetails konfigurierbar machen
[kivitendo-erp.git] / SL / Controller / ClientConfig.pm
1 package SL::Controller::ClientConfig;
2
3 use strict;
4 use parent qw(SL::Controller::Base);
5
6 use File::Copy::Recursive ();
7 use List::Util qw(first);
8
9 use SL::DB::Chart;
10 use SL::DB::Currency;
11 use SL::DB::Default;
12 use SL::DB::Language;
13 use SL::DB::Part;
14 use SL::DB::Unit;
15 use SL::Helper::Flash;
16 use SL::Locale::String qw(t8);
17 use SL::PriceSource::ALL;
18 use SL::Template;
19 use SL::Controller::TopQuickSearch;
20 use SL::Helper::ShippedQty;
21
22 __PACKAGE__->run_before('check_auth');
23
24 use Rose::Object::MakeMethods::Generic (
25   'scalar --get_set_init' => [ qw(defaults all_warehouses all_weightunits all_languages all_currencies all_templates all_price_sources h_unit_name available_quick_search_modules available_shipped_qty_item_identity_fields
26                                   all_project_statuses all_project_types
27                                   posting_options payment_options accounting_options inventory_options profit_options balance_startdate_method_options) ],
28 );
29
30 sub action_edit {
31   my ($self, %params) = @_;
32
33   $::form->{use_templates} = $self->defaults->templates ? 'existing' : 'new';
34   $::form->{feature_datev} = $self->defaults->feature_datev;
35   $self->edit_form;
36 }
37
38 sub action_save {
39   my ($self, %params)      = @_;
40
41   my $defaults             = delete($::form->{defaults}) || {};
42   my $entered_currencies   = delete($::form->{currencies}) || [];
43   my $original_currency_id = $self->defaults->currency_id;
44   $defaults->{disabled_price_sources} ||= [];
45
46   # undef several fields if an empty value has been selected.
47   foreach (qw(warehouse_id bin_id warehouse_id_ignore_onhand bin_id_ignore_onhand)) {
48     undef $defaults->{$_} if !$defaults->{$_};
49   }
50
51   $defaults->{$_} = $::form->parse_amount(\%::myconfig, $defaults->{$_}) for qw(customer_hourly_rate);
52
53   $self->defaults->assign_attributes(%{ $defaults });
54
55   my %errors_idx;
56
57   # Handle currencies
58   my (%new_currency_names);
59   foreach my $existing_currency (@{ $self->all_currencies }) {
60     my $new_name     = $existing_currency->name;
61     my $new_currency = first { $_->{id} == $existing_currency->id } @{ $entered_currencies };
62     $new_name        = $new_currency->{name} if $new_currency;
63
64     if (!$new_name) {
65       $errors_idx{0} = t8('Currency names must not be empty.');
66     } elsif ($new_currency_names{$new_name}) {
67       $errors_idx{1} = t8('Currency names must be unique.');
68     }
69
70     if ($new_name) {
71       $new_currency_names{$new_name} = 1;
72       $existing_currency->name($new_name);
73     }
74   }
75
76   if ($::form->{new_currency} && $new_currency_names{ $::form->{new_currency} }) {
77     $errors_idx{1} = t8('Currency names must be unique.');
78   }
79
80   my @errors = map { $errors_idx{$_} } sort keys %errors_idx;
81
82   # Check templates
83   $::form->{new_templates}        =~ s:/::g;
84   $::form->{new_master_templates} =~ s:/::g;
85
86   if (($::form->{use_templates} eq 'existing') && ($self->defaults->templates !~ m:^templates/[^/]+$:)) {
87     push @errors, t8('You must select existing print templates or create a new set.');
88
89   } elsif ($::form->{use_templates} eq 'new') {
90     if (!$::form->{new_templates}) {
91       push @errors, t8('You must enter a name for your new print templates.');
92     } elsif (-d "templates/" . $::form->{new_templates}) {
93       push @errors, t8('A directory with the name for the new print templates exists already.');
94     } elsif (! -d "templates/print/" . $::form->{new_master_templates}) {
95       push @errors, t8('The master templates where not found.');
96     }
97   }
98
99   # Show form again if there were any errors. Nothing's been changed
100   # yet in the database.
101   if (@errors) {
102     flash('error', @errors);
103     return $self->edit_form;
104   }
105
106   # Save currencies. As the names must be unique we cannot simply save
107   # them as they are -- the user might want to swap to names. So make
108   # them unique first and assign the actual names in a second step.
109   my %currency_names_by_id = map { ($_->id => $_->name) } @{ $self->all_currencies };
110   $_->update_attributes(name => '__039519735__' . $_->{id})        for @{ $self->all_currencies };
111   $_->update_attributes(name => $currency_names_by_id{ $_->{id} }) for @{ $self->all_currencies };
112
113   # Create new currency if required
114   my $new_currency;
115   if ($::form->{new_currency}) {
116     $new_currency = SL::DB::Currency->new(name => $::form->{new_currency});
117     $new_currency->save;
118   }
119
120   # If the user wants the new currency to be the default then replace
121   # the ID placeholder with the proper value. However, if no new
122   # currency has been created then don't change the value at all.
123   if (-1 == $self->defaults->currency_id) {
124     $self->defaults->currency_id($new_currency ? $new_currency->id : $original_currency_id);
125   }
126
127   # Create new templates if requested.
128   if ($::form->{use_templates} eq 'new') {
129     local $File::Copy::Recursive::SkipFlop = 1;
130     File::Copy::Recursive::dircopy('templates/print/' . $::form->{new_master_templates}, 'templates/' . $::form->{new_templates});
131     $self->defaults->templates('templates/' . $::form->{new_templates});
132   }
133
134   # Finally save defaults.
135   $self->defaults->save;
136
137   flash_later('info', t8('Client Configuration saved!'));
138
139   $self->redirect_to(action => 'edit');
140 }
141
142 #
143 # initializers
144 #
145
146 sub init_defaults        { SL::DB::Default->get                                                                          }
147 sub init_all_warehouses  { SL::DB::Manager::Warehouse->get_all_sorted                                                    }
148 sub init_all_languages   { SL::DB::Manager::Language->get_all_sorted                                                     }
149 sub init_all_currencies  { SL::DB::Manager::Currency->get_all_sorted                                                     }
150 sub init_all_weightunits { my $unit = SL::DB::Manager::Unit->find_by(name => 'kg'); $unit ? $unit->convertible_units : [] }
151 sub init_all_templates   { +{ SL::Template->available_templates }                                                        }
152 sub init_h_unit_name     { first { SL::DB::Manager::Unit->find_by(name => $_) } qw(Std h Stunde)                         }
153 sub init_all_project_types    { SL::DB::Manager::ProjectType->get_all_sorted                                             }
154 sub init_all_project_statuses { SL::DB::Manager::ProjectStatus->get_all_sorted                                           }
155
156 sub init_posting_options {
157   [ { title => t8("never"),           value => 0           },
158     { title => t8("every time"),      value => 1           },
159     { title => t8("on the same day"), value => 2           }, ]
160 }
161
162 sub init_payment_options {
163   [ { title => t8("never"),           value => 0           },
164     { title => t8("every time"),      value => 1           },
165     { title => t8("on the same day"), value => 2           }, ]
166 }
167
168 sub init_accounting_options {
169   [ { title => t8("Accrual"),         value => "accrual"   },
170     { title => t8("cash"),            value => "cash"      }, ]
171 }
172
173 sub init_inventory_options {
174   [ { title => t8("perpetual"),       value => "perpetual" },
175     { title => t8("periodic"),        value => "periodic"  }, ]
176 }
177
178 sub init_profit_options {
179   [ { title => t8("balance"),         value => "balance"   },
180     { title => t8("income"),          value => "income"    }, ]
181 }
182
183 sub init_balance_startdate_method_options {
184   [ { title => t8("After closed period"),                       value => "closed_to"                   },
185     { title => t8("Start of year"),                             value => "start_of_year"               },
186     { title => t8("All transactions"),                          value => "all_transactions"            },
187     { title => t8("Last opening balance or all transactions"),  value => "last_ob_or_all_transactions" },
188     { title => t8("Last opening balance or start of year"),     value => "last_ob_or_start_of_year"    }, ]
189 }
190
191 sub init_all_price_sources {
192   my @classes = SL::PriceSource::ALL->all_price_sources;
193
194   [ map { [ $_->name, $_->description ] } @classes ];
195 }
196
197 sub init_available_quick_search_modules {
198   [ SL::Controller::TopQuickSearch->new->available_modules ];
199 }
200
201 sub init_available_shipped_qty_item_identity_fields {
202   [ SL::Helper::ShippedQty->new->available_item_identity_fields ];
203 }
204
205 #
206 # filters
207 #
208
209 sub check_auth {
210   $::auth->assert('admin');
211 }
212
213 #
214 # helpers
215 #
216
217 sub edit_form {
218   my ($self) = @_;
219
220   $::request->layout->use_javascript("${_}.js") for qw(jquery.selectboxes jquery.multiselect2side kivi.File);
221
222   $self->setup_edit_form_action_bar;
223   $self->render('client_config/form', title => t8('Client Configuration'),
224                 make_chart_title     => sub { $_[0]->accno . '--' . $_[0]->description },
225                 make_templates_value => sub { 'templates/' . $_[0] },
226               );
227 }
228
229 sub setup_edit_form_action_bar {
230   my ($self) = @_;
231
232   for my $bar ($::request->layout->get('actionbar')) {
233     $bar->add(
234       action => [
235         t8('Save'),
236         submit    => [ '#form', { action => 'ClientConfig/save' } ],
237         accesskey => 'enter',
238       ],
239     );
240   }
241 }
242
243 1;