test action
[kivitendo-erp.git] / SL / Controller / CsvImport / Helper / Consistency.pm
1 package SL::Controller::CsvImport::Helper::Consistency;
2
3 use strict;
4
5 use Data::Dumper;
6 use SL::DB::Default;
7 use SL::DB::Currency;
8 use SL::DB::TaxZone;
9 use SL::DB::Project;
10 use SL::DB::Department;
11
12 use SL::Helper::Csv::Error;
13
14 use parent qw(Exporter);
15 our @EXPORT = qw(check_currency check_taxzone check_project check_department check_customer_vendor handle_salesman handle_employee);
16
17 #
18 # public functions
19 #
20
21 sub check_currency {
22   my ($self, $entry, %params) = @_;
23
24   my $object = $entry->{object};
25
26   # Check whether or not currency ID is valid.
27   if ($object->currency_id && ! _currencies_by($self)->{id}->{ $object->currency_id }) {
28     push @{ $entry->{errors} }, $::locale->text('Error: Invalid currency');
29     return 0;
30   }
31
32   # Map name to ID if given.
33   if (!$object->currency_id && $entry->{raw_data}->{currency}) {
34     my $currency = _currencies_by($self)->{name}->{  $entry->{raw_data}->{currency} };
35     if (!$currency) {
36       push @{ $entry->{errors} }, $::locale->text('Error: Invalid currency');
37       return 0;
38     }
39
40     $object->currency_id($currency->id);
41
42     # register currency_id for method copying later
43     $self->clone_methods->{currency_id} = 1;
44   }
45
46   # Set default currency if none was given and take_default is true.
47   $object->currency_id(_default_currency_id($self)) if !$object->currency_id and $params{take_default};
48
49   $entry->{raw_data}->{currency_id} = $object->currency_id;
50
51   return 1;
52 }
53
54 sub check_taxzone {
55   my ($self, $entry, %params) = @_;
56
57   my $object = $entry->{object};
58
59   # Check whether the CSV contains the parameters taxzone_id or taxzone, and
60   # check them for validity.
61   # If one of them was given, but is invalid, return an error
62
63   # If neither was given:
64   # a) if param take_default was set, use the taxzone_id from the profile
65   #    (customer/vendor import)
66   # b) if param take_default was not set, do nothing, return without error, and
67   #    taxzone_id may be set later by other means (order import uses cv settings)
68
69
70   # if $object->taxzone_id is defined (from CSV line), check if it is valid
71   if ($object->taxzone_id && ! _taxzones_by($self)->{id}->{ $object->taxzone_id }) {
72     push @{ $entry->{errors} }, $::locale->text('Error: Invalid tax zone');
73     return 0;
74   }
75
76   # if there was no taxzone_id in CSV, but a taxzone entry, check if it is a
77   # valid taxzone and set the id
78   if (!$object->taxzone_id && $entry->{raw_data}->{taxzone}) {
79     my $taxzone = _taxzones_by($self)->{description}->{ $entry->{raw_data}->{taxzone} };
80     if (!$taxzone) {
81       push @{ $entry->{errors} }, $::locale->text('Error: Invalid tax zone');
82       return 0;
83     }
84
85     $object->taxzone_id($taxzone->id);
86   }
87
88   # The take_default option should only be used for the customer/vendor case,
89   # as the default for imported orders is the taxzone according to the customer
90   # or vendor
91   # if neither taxzone_id nor taxzone were defined, use the default taxzone as
92   # defined from the import settings (a default/fallback taxzone that is to be
93   # used will always be selected)
94
95   if (!$object->taxzone_id && $params{take_default}) {
96     # my $default_id = $self->settings->{'default_taxzone'};
97     my $default_id = $self->controller->profile->get('default_taxzone');
98     $default_id ||= _default_taxzone_id($self);
99     $object->taxzone_id($default_id);
100     # check if default taxzone_id is valid just to be sure
101     if (! _taxzones_by($self)->{id}->{ $object->taxzone_id }) {
102       push @{ $entry->{errors} }, $::locale->text('Error with default taxzone');
103       return 0;
104     }
105   };
106
107   # for the order import at this stage $object->taxzone_id may still not be
108   # defined, in this case the customer/vendor taxzone will be used later
109   if ( defined $object->taxzone_id ) {
110     $entry->{info_data}->{taxzone} = _taxzones_by($self)->{id}->{ $object->taxzone_id }->description;
111   };
112
113   return 1;
114 }
115
116 sub check_project {
117   my ($self, $entry, %params) = @_;
118
119   my $id_column          = ($params{global} ? 'global' : '') . 'project_id';
120   my $number_column      = ($params{global} ? 'global' : '') . 'projectnumber';
121   my $description_column = ($params{global} ? 'global' : '') . 'project';
122
123   my $object = $entry->{object};
124
125   # Check whether or not project ID is valid.
126   if ($object->$id_column) {
127     if (! _projects_by($self)->{id}->{ $object->$id_column }) {
128       push @{ $entry->{errors} }, $::locale->text('Error: Invalid project');
129       return 0;
130     } else {
131       $entry->{info_data}->{$number_column} = _projects_by($self)->{id}->{ $object->$id_column }->description;
132     };
133   }
134
135   my $proj;
136   # Map number to ID if given.
137   if (!$object->$id_column && $entry->{raw_data}->{$number_column}) {
138     $proj = _projects_by($self)->{projectnumber}->{ $entry->{raw_data}->{$number_column} };
139     if (!$proj) {
140       push @{ $entry->{errors} }, $::locale->text('Error: Invalid project');
141       return 0;
142     }
143
144     $object->$id_column($proj->id);
145   }
146
147   # Map description to ID if given.
148   if (!$object->$id_column && $entry->{raw_data}->{$description_column}) {
149     $proj = _projects_by($self)->{description}->{ $entry->{raw_data}->{$description_column} };
150     if (!$proj) {
151       push @{ $entry->{errors} }, $::locale->text('Error: Invalid project');
152       return 0;
153     }
154
155     $object->$id_column($proj->id);
156   }
157
158   if ( $proj ) {
159     $entry->{info_data}->{"$description_column"} = $proj->description;
160     $entry->{info_data}->{"$number_column"}      = $proj->projectnumber;
161   };
162
163   return 1;
164 }
165
166 sub check_department {
167   my ($self, $entry) = @_;
168
169   my $object = $entry->{object};
170
171   # Check whether or not department ID was assigned and is valid.
172   if ($object->department_id) {
173     if (!_departments_by($self)->{id}->{ $object->department_id }) {
174       push @{ $entry->{errors} }, $::locale->text('Error: Invalid department');
175       return 0;
176     } else {
177       # add department description as well, more feedback for user
178       $entry->{info_data}->{department} = _departments_by($self)->{id}->{ $object->department_id }->description;
179     };
180   }
181
182   # Map department description to ID if given.
183   if (!$object->department_id && $entry->{raw_data}->{department}) {
184     $entry->{info_data}->{department} = $entry->{raw_data}->{department};
185     my $dep = _departments_by($self)->{description}->{ $entry->{raw_data}->{department} };
186     if (!$dep) {
187       push @{ $entry->{errors} }, $::locale->text('Error: Invalid department');
188       return 0;
189     }
190     $entry->{info_data}->{department} = $dep->description;
191     $object->department_id($dep->id);
192   }
193
194   return 1;
195 }
196
197 # ToDo: salesman by name
198 sub handle_salesman {
199   my ($self, $entry) = @_;
200
201   my $object = $entry->{object};
202   my $vc_obj;
203   $vc_obj    = SL::DB::Customer->new(id => $object->customer_id)->load if $object->can('customer') && $object->customer_id;
204   $vc_obj    = SL::DB::Vendor->new(id   => $object->vendor_id)->load   if (!$vc_obj && $object->can('vendor') && $object->vendor_id);
205
206   # salesman from customer/vendor or login if not given
207   if (!$object->salesman) {
208     if ($vc_obj && $vc_obj->salesman_id) {
209       $object->salesman(SL::DB::Manager::Employee->find_by(id => $vc_obj->salesman_id));
210     } else {
211       $object->salesman(SL::DB::Manager::Employee->find_by(login => $::myconfig{login}));
212     }
213   }
214 }
215
216 # ToDo: employee by name
217 sub handle_employee {
218   my ($self, $entry) = @_;
219
220   my $object = $entry->{object};
221
222   # employee from front end if not given
223   if (!$object->employee_id) {
224     $object->employee_id($self->controller->{employee_id});
225   }
226   # employee from login if not given
227   if (!$object->employee_id) {
228     $object->employee_id(SL::DB::Manager::Employee->current->id) if SL::DB::Manager::Employee->current;
229   }
230 }
231
232
233
234 #
235 # private functions
236 #
237
238 sub _currencies_by {
239   my ($self) = @_;
240
241   return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ _all_currencies($self) } } ) } qw(id name) };
242 }
243
244 sub _all_currencies {
245   my ($self) = @_;
246
247   return SL::DB::Manager::Currency->get_all;
248 }
249
250 sub _default_currency_id {
251   my ($self) = @_;
252
253   return SL::DB::Default->get->currency_id;
254 }
255
256 sub _default_taxzone_id {
257   my ($self) = @_;
258
259   return SL::DB::Manager::TaxZone->get_all_sorted(query => [ obsolete => 0 ])->[0]->id;
260 }
261
262 sub _departments_by {
263   my ($self) = @_;
264
265   my $all_departments = SL::DB::Manager::Department->get_all;
266   return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $all_departments } } ) } qw(id description) };
267 }
268
269 sub _projects_by {
270   my ($self) = @_;
271
272   my $all_projects = SL::DB::Manager::Project->get_all;
273   return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $all_projects } } ) } qw(id projectnumber description) };
274 }
275
276 sub _taxzones_by {
277   my ($self) = @_;
278
279   return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ _all_taxzones($self) } } ) } qw(id description) };
280 }
281
282 sub _all_taxzones {
283   my ($self) = @_;
284
285   return SL::DB::Manager::TaxZone->get_all_sorted(query => [ obsolete => 0 ]);
286 }
287
288 1;