Preisfaktoren und Preisgruppen behandeln.
[kivitendo-erp.git] / SL / Controller / CsvImport / Order.pm
1 package SL::Controller::CsvImport::Order;
2
3
4 use strict;
5
6 use List::MoreUtils qw(any);
7
8 use SL::Helper::Csv;
9 use SL::DB::Order;
10 use SL::DB::OrderItem;
11 use SL::DB::Part;
12 use SL::DB::PaymentTerm;
13 use SL::DB::Contact;
14 use SL::DB::Department;
15 use SL::DB::PriceFactor;
16 use SL::DB::Pricegroup;
17 use SL::DB::Project;
18 use SL::DB::Shipto;
19 use SL::DB::TaxZone;
20 use SL::TransNumber;
21
22 use parent qw(SL::Controller::CsvImport::BaseMulti);
23
24
25 use Rose::Object::MakeMethods::Generic
26 (
27  'scalar --get_set_init' => [ qw(settings languages_by parts_by contacts_by departments_by projects_by ct_shiptos_by taxzones_by price_factors_by pricegroups_by) ],
28 );
29
30
31 sub init_class {
32   my ($self) = @_;
33   $self->class(['SL::DB::Order', 'SL::DB::OrderItem']);
34 }
35
36
37 sub init_settings {
38   my ($self) = @_;
39
40   return { map { ( $_ => $self->controller->profile->get($_) ) } qw(order_column item_column) };
41 }
42
43
44 sub init_profile {
45   my ($self) = @_;
46
47   my $profile = $self->SUPER::init_profile;
48
49   foreach my $p (@{ $profile }) {
50     my $prof = $p->{profile};
51     if ($p->{row_ident} eq 'Order') {
52       # no need to handle
53       delete @{$prof}{qw(delivery_customer_id delivery_vendor_id proforma quotation amount netamount)};
54       # handable, but not handled by now
55     }
56     if ($p->{row_ident} eq 'OrderItem') {
57       delete @{$prof}{qw(trans_id)};
58     }
59   }
60
61   return $profile;
62 }
63
64
65 sub setup_displayable_columns {
66   my ($self) = @_;
67
68   $self->SUPER::setup_displayable_columns;
69
70   $self->add_displayable_columns('Order',
71                                  { name => 'datatype',         description => $::locale->text('Zeilenkennung')                  },
72                                  { name => 'verify_amount',    description => $::locale->text('Amount (for verification)')      },
73                                  { name => 'verify_netamount', description => $::locale->text('Net amount (for verification)')  },
74                                  { name => 'taxincluded',      description => $::locale->text('Tax Included')                   },
75                                  { name => 'customer',         description => $::locale->text('Customer (name)')                },
76                                  { name => 'customernumber',   description => $::locale->text('Customer Number')                },
77                                  { name => 'customer_id',      description => $::locale->text('Customer (database ID)')         },
78                                  { name => 'vendor',           description => $::locale->text('Vendor (name)')                  },
79                                  { name => 'vendornumber',     description => $::locale->text('Vendor Number')                  },
80                                  { name => 'vendor_id',        description => $::locale->text('Vendor (database ID)')           },
81                                  { name => 'language_id',      description => $::locale->text('Language (database ID)')         },
82                                  { name => 'language',         description => $::locale->text('Language (name)')                },
83                                  { name => 'payment_id',       description => $::locale->text('Payment terms (database ID)')    },
84                                  { name => 'payment',          description => $::locale->text('Payment terms (name)')           },
85                                  { name => 'taxzone_id',       description => $::locale->text('Steuersatz (database ID')        },
86                                  { name => 'taxzone',          description => $::locale->text('Steuersatz (description)')       },
87                                  { name => 'cp_id',            description => $::locale->text('Contact Person (database ID)')   },
88                                  { name => 'contact',          description => $::locale->text('Contact Person (name)')          },
89                                  { name => 'department_id',    description => $::locale->text('Department (database ID)')       },
90                                  { name => 'department',       description => $::locale->text('Department (description)')       },
91                                  { name => 'globalproject_id', description => $::locale->text('Document Project (database ID)') },
92                                  { name => 'globalprojectnumber', description => $::locale->text('Document Project (number)')   },
93                                  { name => 'globalproject',    description => $::locale->text('Document Project (description)') },
94                                  { name => 'shipto_id',        description => $::locale->text('Ship to (database ID)')          },
95                                 );
96
97   $self->add_displayable_columns('OrderItem',
98                                  { name => 'parts_id',        description => $::locale->text('Part (database ID)')         },
99                                  { name => 'partnumber',      description => $::locale->text('Part Number')                },
100                                  { name => 'project_id',      description => $::locale->text('Project (database ID)')      },
101                                  { name => 'projectnumber',   description => $::locale->text('Project (number)')           },
102                                  { name => 'project',         description => $::locale->text('Project (description)')      },
103                                  { name => 'price_factor_id', description => $::locale->text('Price factor (database ID)') },
104                                  { name => 'price_factor',    description => $::locale->text('Price factor (name)')        },
105                                  { name => 'pricegroup_id',   description => $::locale->text('Price group (database ID)')  },
106                                  { name => 'pricegroup',      description => $::locale->text('Price group (name)')         },
107                                 );
108 }
109
110
111 sub init_languages_by {
112   my ($self) = @_;
113
114   return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $self->all_languages } } ) } qw(id description article_code) };
115 }
116
117 sub init_parts_by {
118   my ($self) = @_;
119
120   my $all_parts = SL::DB::Manager::Part->get_all;
121   return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $all_parts } } ) } qw(id partnumber ean description) };
122 }
123
124 sub init_contacts_by {
125   my ($self) = @_;
126
127   my $all_contacts = SL::DB::Manager::Contact->get_all;
128
129   my $cby;
130   # by customer/vendor id  _and_  contact person id
131   $cby->{'cp_cv_id+cp_id'}   = { map { ( $_->cp_cv_id . '+' . $_->cp_id   => $_ ) } @{ $all_contacts } };
132   # by customer/vendor id  _and_  contact person name
133   $cby->{'cp_cv_id+cp_name'} = { map { ( $_->cp_cv_id . '+' . $_->cp_name => $_ ) } @{ $all_contacts } };
134
135   return $cby;
136 }
137
138 sub init_departments_by {
139   my ($self) = @_;
140
141   my $all_departments = SL::DB::Manager::Department->get_all;
142   return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $all_departments } } ) } qw(id description) };
143 }
144
145 sub init_projects_by {
146   my ($self) = @_;
147
148   my $all_projects = SL::DB::Manager::Project->get_all;
149   return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $all_projects } } ) } qw(id projectnumber description) };
150 }
151
152 sub init_ct_shiptos_by {
153   my ($self) = @_;
154
155   my $all_ct_shiptos = SL::DB::Manager::Shipto->get_all(query => [module => 'CT']);
156
157   my $sby;
158   # by trans_id  _and_  shipto_id
159   $sby->{'trans_id+shipto_id'} = { map { ( $_->trans_id . '+' . $_->shipto_id => $_ ) } @{ $all_ct_shiptos } };
160
161   return $sby;
162 }
163
164 sub init_taxzones_by {
165   my ($self) = @_;
166
167   my $all_taxzones = SL::DB::Manager::TaxZone->get_all;
168   return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $all_taxzones } } ) } qw(id description) };
169 }
170
171 sub init_price_factors_by {
172   my ($self) = @_;
173
174   my $all_price_factors = SL::DB::Manager::PriceFactor->get_all;
175   return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $all_price_factors } } ) } qw(id description) };
176 }
177
178 sub init_pricegroups_by {
179   my ($self) = @_;
180
181   my $all_pricegroups = SL::DB::Manager::Pricegroup->get_all;
182   return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $all_pricegroups } } ) } qw(id pricegroup) };
183 }
184
185 sub check_objects {
186   my ($self) = @_;
187
188   $self->controller->track_progress(phase => 'building data', progress => 0);
189
190   my $i;
191   my $num_data = scalar @{ $self->controller->data };
192   foreach my $entry (@{ $self->controller->data }) {
193     $self->controller->track_progress(progress => $i/$num_data * 100) if $i % 100 == 0;
194
195     if ($entry->{raw_data}->{datatype} eq $self->settings->{'order_column'}) {
196
197       my $vc_obj;
198       if (any { $entry->{raw_data}->{$_} } qw(customer customernumber customer_id)) {
199         $self->check_vc($entry, 'customer_id');
200         $vc_obj = SL::DB::Customer->new(id => $entry->{object}->customer_id)->load if $entry->{object}->customer_id;
201       } elsif (any { $entry->{raw_data}->{$_} } qw(vendor vendornumber vendor_id)) {
202         $self->check_vc($entry, 'vendor_id');
203         $vc_obj = SL::DB::Vendor->new(id => $entry->{object}->vendor_id)->load if $entry->{object}->vendor_id;
204       } else {
205         push @{ $entry->{errors} }, $::locale->text('Error: Customer/vendor missing');
206       }
207
208       $self->check_contact($entry);
209       $self->check_language($entry);
210       $self->check_payment($entry);
211       $self->check_department($entry);
212       $self->check_project($entry, global => 1);
213       $self->check_ct_shipto($entry);
214       $self->check_taxzone($entry);
215
216       if ($vc_obj) {
217         # copy from customer if not given
218         foreach (qw(payment_id language_id taxzone_id)) {
219           $entry->{object}->$_($vc_obj->$_) unless $entry->{object}->$_;
220         }
221       }
222
223       # ToDo: salesman and emloyee by name
224       # salesman from customer or login if not given
225       if (!$entry->{object}->salesman) {
226         if ($vc_obj && $vc_obj->salesman_id) {
227           $entry->{object}->salesman(SL::DB::Manager::Employee->find_by(id => $vc_obj->salesman_id));
228         } else {
229           $entry->{object}->salesman(SL::DB::Manager::Employee->find_by(login => $::myconfig{login}));
230         }
231       }
232
233       # employee from login if not given
234       if (!$entry->{object}->employee_id) {
235         $entry->{object}->employee_id(SL::DB::Manager::Employee->find_by(login => $::myconfig{login})->id);
236       }
237
238     }
239   }
240
241   $self->add_info_columns($self->settings->{'order_column'},
242                           { header => $::locale->text('Customer/Vendor'), method => 'vc_name' });
243   # Todo: access via ->[0] ok? Better: search first order column and use this
244   $self->add_columns($self->settings->{'order_column'},
245                      map { "${_}_id" } grep { exists $self->controller->data->[0]->{raw_data}->{$_} } qw(payment language department globalproject taxzone cp));
246   $self->add_columns($self->settings->{'order_column'}, 'globalproject_id') if exists $self->controller->data->[0]->{raw_data}->{globalprojectnumber};
247   $self->add_columns($self->settings->{'order_column'}, 'cp_id')            if exists $self->controller->data->[0]->{raw_data}->{contact};
248
249   foreach my $entry (@{ $self->controller->data }) {
250     if ($entry->{raw_data}->{datatype} eq $self->settings->{'item_column'} && $entry->{object}->can('part')) {
251
252       next if !$self->check_part($entry);
253
254       my $part_obj = SL::DB::Part->new(id => $entry->{object}->parts_id)->load;
255
256       # copy from part if not given
257       $entry->{object}->description($part_obj->description) unless $entry->{object}->description;
258       $entry->{object}->longdescription($part_obj->notes)   unless $entry->{object}->longdescription;
259       $entry->{object}->unit($part_obj->unit)               unless $entry->{object}->unit;
260
261       # set to 0 if not given
262       $entry->{object}->discount(0)      unless $entry->{object}->discount;
263       $entry->{object}->ship(0)          unless $entry->{object}->ship;
264
265       $self->check_project($entry, global => 0);
266       $self->check_price_factor($entry);
267       $self->check_pricegroup($entry);
268       
269     }
270   }
271
272   $self->add_info_columns($self->settings->{'item_column'},
273                           { header => $::locale->text('Part Number'), method => 'partnumber' });
274   # Todo: access via ->[1] ok? Better: search first item column and use this
275   $self->add_columns($self->settings->{'item_column'},
276                      map { "${_}_id" } grep { exists $self->controller->data->[1]->{raw_data}->{$_} } qw(project price_factor pricegroup));
277   $self->add_columns($self->settings->{'item_column'}, 'project_id') if exists $self->controller->data->[1]->{raw_data}->{projectnumber};
278
279   # add orderitems to order
280   my $order_entry;
281   my @orderitems;
282   foreach my $entry (@{ $self->controller->data }) {
283     # search first Order
284     if ($entry->{raw_data}->{datatype} eq $self->settings->{'order_column'}) {
285
286       # new order entry: add collected orderitems to the last one
287       if (defined $order_entry) {
288         $order_entry->{object}->orderitems(@orderitems);
289         @orderitems = ();
290       }
291
292       $order_entry = $entry;
293
294     } elsif ( defined $order_entry && $entry->{raw_data}->{datatype} eq $self->settings->{'item_column'} ) {
295       # collect orderitems to add to order (if they have no errors)
296       # ( add_orderitems does not work here if we want to call
297       #   calculate_prices_and_taxes afterwards ...
298       #   so collect orderitems and add them at once)
299       if (scalar @{ $entry->{errors} } == 0) {
300         push @orderitems, $entry->{object};
301       }
302     }
303   }
304   # add last collected orderitems to last order
305   if ($order_entry) {
306     $order_entry->{object}->orderitems(@orderitems);
307   }
308
309   # calculate prices and taxes
310   foreach my $entry (@{ $self->controller->data }) {
311     next if @{ $entry->{errors} };
312
313     if ($entry->{raw_data}->{datatype} eq $self->settings->{'order_column'}) {
314
315       $entry->{object}->calculate_prices_and_taxes;
316
317       $entry->{info_data}->{calc_amount}    = $entry->{object}->amount_as_number;
318       $entry->{info_data}->{calc_netamount} = $entry->{object}->netamount_as_number;
319     }
320   }
321
322   # If amounts are given, show calculated amounts as info and given amounts (verify_xxx).
323   # And throw an error if the differences are too big.
324   my $max_diff = 0.02;
325   my @to_verify = ( { column      => 'amount',
326                       raw_column  => 'verify_amount',
327                       info_header => 'Calc. Amount',
328                       info_method => 'calc_amount',
329                       err_msg     => 'Amounts differ too much',
330                     },
331                     { column      => 'netamount',
332                       raw_column  => 'verify_netamount',
333                       info_header => 'Calc. Net amount',
334                       info_method => 'calc_netamount',
335                       err_msg     => 'Net amounts differ too much',
336                     } );
337
338   foreach my $tv (@to_verify) {
339     # Todo: access via ->[0] ok? Better: search first order column and use this
340     if (exists $self->controller->data->[0]->{raw_data}->{ $tv->{raw_column} }) {
341       $self->add_raw_data_columns($self->settings->{'order_column'}, $tv->{raw_column});
342       $self->add_info_columns($self->settings->{'order_column'},
343                               { header => $::locale->text($tv->{info_header}), method => $tv->{info_method} });
344     }
345
346     # check differences
347     foreach my $entry (@{ $self->controller->data }) {
348       next if @{ $entry->{errors} };
349       if ($entry->{raw_data}->{datatype} eq $self->settings->{'order_column'}) {
350         next if !$entry->{raw_data}->{ $tv->{raw_column} };
351         my $parsed_value = $::form->parse_amount(\%::myconfig, $entry->{raw_data}->{ $tv->{raw_column} });
352         if (abs($entry->{object}->${ \$tv->{column} } - $parsed_value) > $max_diff) {
353           push @{ $entry->{errors} }, $::locale->text($tv->{err_msg});
354         }
355       }
356     }
357   }
358
359   # If order has errors set error for orderitems as well
360   my $order_entry;
361   foreach my $entry (@{ $self->controller->data }) {
362     # Search first order
363     if ($entry->{raw_data}->{datatype} eq $self->settings->{'order_column'}) {
364       $order_entry = $entry;
365     } elsif ( defined $order_entry
366               && $entry->{raw_data}->{datatype} eq $self->settings->{'item_column'}
367               && scalar @{ $order_entry->{errors} } > 0 ) {
368       push @{ $entry->{errors} }, $::locale->text('order not valid for this orderitem!');
369     }
370   }
371
372 }
373
374
375 sub check_language {
376   my ($self, $entry) = @_;
377
378   my $object = $entry->{object};
379
380   # Check whether or not language ID is valid.
381   if ($object->language_id && !$self->languages_by->{id}->{ $object->language_id }) {
382     push @{ $entry->{errors} }, $::locale->text('Error: Invalid language');
383     return 0;
384   }
385
386   # Map name to ID if given.
387   if (!$object->language_id && $entry->{raw_data}->{language}) {
388     my $language = $self->languages_by->{description}->{  $entry->{raw_data}->{language} }
389                 || $self->languages_by->{article_code}->{ $entry->{raw_data}->{language} };
390
391     if (!$language) {
392       push @{ $entry->{errors} }, $::locale->text('Error: Invalid language');
393       return 0;
394     }
395
396     $object->language_id($language->id);
397   }
398
399   if ($object->language_id) {
400     $entry->{info_data}->{language} = $self->languages_by->{id}->{ $object->language_id }->description;
401   }
402
403   return 1;
404 }
405
406 sub check_part {
407   my ($self, $entry) = @_;
408
409   my $object = $entry->{object};
410
411   # Check wether or non part ID is valid.
412   if ($object->parts_id && !$self->parts_by->{id}->{ $object->parts_id }) {
413     push @{ $entry->{errors} }, $::locale->text('Error: Invalid part');
414     return 0;
415   }
416
417   # Map number to ID if given.
418   if (!$object->parts_id && $entry->{raw_data}->{partnumber}) {
419     my $part = $self->parts_by->{partnumber}->{ $entry->{raw_data}->{partnumber} };
420     if (!$part) {
421       push @{ $entry->{errors} }, $::locale->text('Error: Invalid part');
422       return 0;
423     }
424
425     $object->parts_id($part->id);
426   }
427
428   if ($object->parts_id) {
429     $entry->{info_data}->{partnumber} = $self->parts_by->{id}->{ $object->parts_id }->partnumber;
430   } else {
431     push @{ $entry->{errors} }, $::locale->text('Error: Part not found');
432     return 0;
433   }
434
435   return 1;
436 }
437
438 sub check_contact {
439   my ($self, $entry) = @_;
440
441   my $object = $entry->{object};
442
443   my $cp_cv_id = $object->customer_id || $object->vendor_id;
444   return 0 unless $cp_cv_id;
445
446   # Check wether or not contact ID is valid.
447   if ($object->cp_id && !$self->contacts_by->{'cp_cv_id+cp_id'}->{ $cp_cv_id . '+' . $object->cp_id }) {
448     push @{ $entry->{errors} }, $::locale->text('Error: Invalid contact');
449     return 0;
450   }
451
452   # Map name to ID if given.
453   if (!$object->cp_id && $entry->{raw_data}->{contact}) {
454     my $cp = $self->contacts_by->{'cp_cv_id+cp_name'}->{ $cp_cv_id . '+' . $entry->{raw_data}->{contact} };
455     if (!$cp) {
456       push @{ $entry->{errors} }, $::locale->text('Error: Invalid contact');
457       return 0;
458     }
459
460     $object->cp_id($cp->cp_id);
461   }
462
463   if ($object->cp_id) {
464     $entry->{info_data}->{contact} = $self->contacts_by->{'cp_cv_id+cp_id'}->{ $cp_cv_id . '+' . $object->cp_id }->cp_name;
465   }
466
467   return 1;
468 }
469
470 sub check_department {
471   my ($self, $entry) = @_;
472
473   my $object = $entry->{object};
474
475   # Check wether or not department ID is valid.
476   if ($object->department_id && !$self->departments_by->{id}->{ $object->department_id }) {
477     push @{ $entry->{errors} }, $::locale->text('Error: Invalid department');
478     return 0;
479   }
480
481   # Map description to ID if given.
482   if (!$object->department_id && $entry->{raw_data}->{department}) {
483     my $dep = $self->departments_by->{description}->{ $entry->{raw_data}->{department} };
484     if (!$dep) {
485       push @{ $entry->{errors} }, $::locale->text('Error: Invalid department');
486       return 0;
487     }
488
489     $object->department_id($dep->id);
490   }
491
492   return 1;
493 }
494
495 sub check_project {
496   my ($self, $entry, %params) = @_;
497
498   my $id_column          = ($params{global} ? 'global' : '') . 'project_id';
499   my $number_column      = ($params{global} ? 'global' : '') . 'projectnumber';
500   my $description_column = ($params{global} ? 'global' : '') . 'project';
501
502   my $object = $entry->{object};
503
504   # Check wether or not projetc ID is valid.
505   if ($object->$id_column && !$self->projects_by->{id}->{ $object->$id_column }) {
506     push @{ $entry->{errors} }, $::locale->text('Error: Invalid project');
507     return 0;
508   }
509
510   # Map number to ID if given.
511   if (!$object->$id_column && $entry->{raw_data}->{$number_column}) {
512     my $proj = $self->projects_by->{projectnumber}->{ $entry->{raw_data}->{$number_column} };
513     if (!$proj) {
514       push @{ $entry->{errors} }, $::locale->text('Error: Invalid project');
515       return 0;
516     }
517
518     $object->$id_column($proj->id);
519   }
520
521   # Map description to ID if given.
522   if (!$object->$id_column && $entry->{raw_data}->{$description_column}) {
523     my $proj = $self->projects_by->{description}->{ $entry->{raw_data}->{$description_column} };
524     if (!$proj) {
525       push @{ $entry->{errors} }, $::locale->text('Error: Invalid project');
526       return 0;
527     }
528
529     $object->$id_column($proj->id);
530   }
531
532   return 1;
533 }
534
535 sub check_ct_shipto {
536   my ($self, $entry) = @_;
537
538   my $object = $entry->{object};
539
540   my $trans_id = $object->customer_id || $object->vendor_id;
541   return 0 unless $trans_id;
542
543   # Check wether or not shipto ID is valid.
544   if ($object->shipto_id && !$self->ct_shiptos_by->{'trans_id+shipto_id'}->{ $trans_id . '+' . $object->shipto_id }) {
545     push @{ $entry->{errors} }, $::locale->text('Error: Invalid shipto');
546     return 0;
547   }
548
549   return 1;
550 }
551
552 sub check_taxzone {
553   my ($self, $entry) = @_;
554
555   my $object = $entry->{object};
556
557   # Check wether or not taxzone ID is valid.
558   if ($object->taxzone_id && !$self->taxzones_by->{id}->{ $object->taxzone_id }) {
559     push @{ $entry->{errors} }, $::locale->text('Error: Invalid taxzone');
560     return 0;
561   }
562
563   # Map description to ID if given.
564   if (!$object->taxzone_id && $entry->{raw_data}->{taxzone}) {
565     my $taxzone = $self->taxzones_by->{description}->{ $entry->{raw_data}->{taxzone} };
566     if (!$taxzone) {
567       push @{ $entry->{errors} }, $::locale->text('Error: Invalid taxzone');
568       return 0;
569     }
570
571     $object->taxzone_id($taxzone->id);
572   }
573
574   return 1;
575 }
576
577
578 sub check_price_factor {
579   my ($self, $entry) = @_;
580
581   my $object = $entry->{object};
582
583   # Check wether or not price_factor ID is valid.
584   if ($object->price_factor_id && !$self->price_factors_by->{id}->{ $object->price_factor_id }) {
585     push @{ $entry->{errors} }, $::locale->text('Error: Invalid price factor');
586     return 0;
587   }
588
589   # Map description to ID if given.
590   if (!$object->price_factor_id && $entry->{raw_data}->{price_factor}) {
591     my $price_factor = $self->price_factors_by->{description}->{ $entry->{raw_data}->{price_factor} };
592     if (!$price_factor) {
593       push @{ $entry->{errors} }, $::locale->text('Error: Invalid price factor');
594       return 0;
595     }
596
597     $object->price_factor_id($price_factor->id);
598   }
599
600   return 1;
601 }
602
603 sub check_pricegroup {
604   my ($self, $entry) = @_;
605
606   my $object = $entry->{object};
607
608   # Check wether or not pricegroup ID is valid.
609   if ($object->pricegroup_id && !$self->pricegroups_by->{id}->{ $object->pricegroup_id }) {
610     push @{ $entry->{errors} }, $::locale->text('Error: Invalid price group');
611     return 0;
612   }
613
614   # Map pricegroup to ID if given.
615   if (!$object->pricegroup_id && $entry->{raw_data}->{pricegroup}) {
616     my $pricegroup = $self->pricegroups_by->{pricegroup}->{ $entry->{raw_data}->{pricegroup} };
617     if (!$pricegroup) {
618       push @{ $entry->{errors} }, $::locale->text('Error: Invalid price group');
619       return 0;
620     }
621
622     $object->pricegroup_id($pricegroup->id);
623   }
624
625   return 1;
626 }
627
628
629 sub save_objects {
630   my ($self, %params) = @_;
631
632   # set order number and collect to save
633   my $objects_to_save;
634   foreach my $entry (@{ $self->controller->data }) {
635     next if @{ $entry->{errors} };
636
637     if ($entry->{raw_data}->{datatype} eq $self->settings->{'order_column'} && !$entry->{object}->ordnumber) {
638       my $number = SL::TransNumber->new(type        => 'sales_order',
639                                         save        => 1);
640       $entry->{object}->ordnumber($number->create_unique());
641     }
642
643     push @{ $objects_to_save }, $entry;
644   }
645
646   $self->SUPER::save_objects(data => $objects_to_save);
647 }
648
649
650 1;