Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 5067d7bd

Von Martin Helmling martin.helmling@octosoft.eu vor etwa 8 Jahren hinzugefügt

  • ID 5067d7bd31514962af9730b33323b831d87164f8
  • Vorgänger 351de256
  • Nachfolger 815c3639

Artikel-Klassifizierung

Die ursprünglich als "Artikeltyp" bezeichnete Klassifizierung von Artikeln
Sie dient einer weiteren Gliederung um zum Beispiel den Einkauf vom Verkauf zu trennen, etc.

Gekennzeichnet durch eine Beschreibung (z.B. "Einkauf") und ein Kürzel (z.B. "E")
Flexibel änderbar und erweiterbar.

- Neue Datenbanktablle und Rose-Objekte, sowie Controller zum Bearbeiten der Tabelle

- Zwei-Zeichen Abkürzung:

Der Typ des Artikel und die Klassifizierung werden durch zwei Buchstaben dargestellt.
Der erste Buchstabe ist eine Lokalisierung des Typs des Artikel ('P','A','S') ,
deutch 'W', 'E', und 'D' für Ware Erzeugnis oder Dienstleistung, ggf. weitere Typen.
Der zweite Buchstabe ist eine Lokalisierung der Klassifizierungsabkürzung (abbreviation).

Die Abkürzungen sind aus dem Part Presenter abholbar:
- SL::Presenter::Part->type_abbreviation($part_type)
- SL::Presenter::Part->classification_abbreviation($classification_id)

Wenn im ERP-Dokument nach einer Artikelnummer oder Beschreibung gesucht wird,
diese in den Stammdaten vorhanden ist,
aber der Artikeltyp leer oder falsch ist, bzw im Typ for_purchase bzw for_sale nicht gesetzt ist,
wird die Fehlermeldung "Gesuchter Artikel ist nicht für den Einkauf bzw Verkauf" gemeldet

Anpassung des CSV Import,
nun wird alternativ zur 'type'-Spalte die 'pclass'-Spalte mit zwei Buchstaben geparsed und entsprechend
classification_id,assembly sowie inventory_accno_id gesetzt (oder type_id falls neue Implementierung eingebaut).

Unterschiede anzeigen:

SL/Controller/CsvImport/Part.pm
23 23
use Rose::Object::MakeMethods::Generic
24 24
(
25 25
 scalar                  => [ qw(table makemodel_columns) ],
26
 'scalar --get_set_init' => [ qw(bg_by settings parts_by price_factors_by units_by partsgroups_by
26
 'scalar --get_set_init' => [ qw(bg_by settings parts_by price_factors_by classification_by units_by partsgroups_by
27 27
                                 warehouses_by bins_by
28 28
                                 translation_columns all_pricegroups) ],
29 29
);
......
40 40
                       article_number_policy     => 'update_prices',
41 41
                       shoparticle_if_missing    => '0',
42 42
                       part_type                 => 'part',
43
                       parts_classification      => 0,
43 44
                       default_buchungsgruppe    => ($bugru ? $bugru->id : undef),
44 45
                       apply_buchungsgruppe      => 'all',
45 46
                      );
......
58 59
  return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $all_bg } } ) } qw(id description) };
59 60
}
60 61

  
62
sub init_classification_by {
63
  my ($self) = @_;
64
  my $all_classifications = SL::DB::Manager::PartsClassification->get_all;
65
  $_->abbreviation($::locale->text($_->abbreviation)) for @{ $all_classifications };
66
  return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $all_classifications } } ) } qw(id abbreviation) };
67
}
68

  
61 69
sub init_price_factors_by {
62 70
  my ($self) = @_;
63 71

  
......
126 134

  
127 135
  return { map { ( $_ => $self->controller->profile->get($_) ) } qw(apply_buchungsgruppe default_buchungsgruppe article_number_policy
128 136
                                                                    sellprice_places sellprice_adjustment sellprice_adjustment_type
129
                                                                    shoparticle_if_missing part_type default_unit) };
137
                                                                    shoparticle_if_missing part_type classification_id default_unit) };
130 138
}
131 139

  
132 140
sub init_all_cvar_configs {
......
174 182
    $i++;
175 183
  }
176 184

  
177
  $self->add_columns(qw(part_type)) if $self->settings->{part_type} eq 'mixed';
185
  $self->add_columns(qw(part_type classification_id)) if $self->settings->{part_type} eq 'mixed';
178 186
  $self->add_columns(qw(buchungsgruppen_id unit));
179 187
  $self->add_columns(map { "${_}_id" } grep { exists $self->controller->data->[0]->{raw_data}->{$_} } qw (price_factor payment partsgroup warehouse bin));
180 188
  $self->add_columns(qw(shop)) if $self->settings->{shoparticle_if_missing};
......
413 421
  # $bg  ||= SL::DB::Buchungsgruppe->new(inventory_accno_id => 1); # does this case ever occur?
414 422

  
415 423
  my $part_type = $self->settings->{part_type};
416
  if ($part_type eq 'mixed') {
424
  if ($part_type eq 'mixed' && $entry->{raw_data}->{part_type}) {
417 425
    $part_type = $entry->{raw_data}->{part_type} =~ m/^p/i ? 'part'
418 426
               : $entry->{raw_data}->{part_type} =~ m/^s/i ? 'service'
419 427
               : $entry->{raw_data}->{part_type} =~ m/^assem/i ? 'assembly'
420 428
               : $entry->{raw_data}->{part_type} =~ m/^assor/i ? 'assortment'
421
               : undef;
429
               : $self->settings->{part_type};
430
  }
431
  my $classification_id = $self->settings->{classification_id};
432

  
433
  if ( $entry->{raw_data}->{pclass} && length($entry->{raw_data}->{pclass}) >= 2 ) {
434
      my $abbr1 = substr($entry->{raw_data}->{pclass},0,1);
435
      my $abbr2 = substr($entry->{raw_data}->{pclass},1);
436

  
437
      if ( $self->classification_by->{abbreviation}->{$abbr2} ) {
438
         my $tmp_classification_id = $self->classification_by->{abbreviation}->{$abbr2}->id;
439
         $classification_id = $tmp_classification_id if $tmp_classification_id;
440
      }
441
      if ($part_type eq 'mixed') {
442
          $part_type = $abbr1 eq $::locale->text('Part (typeabbreviation)') ? 'part'
443
                     : $abbr1 eq $::locale->text('Service (typeabbreviation)') ? 'service'
444
                     : $abbr1 eq $::locale->text('Assembly (typeabbreviation)') ? 'assembly'
445
                     : $abbr1 eq $::locale->text('Assortment (typeabbreviation)') ? 'assortment'
446
                     :                                        undef;
447
      }
422 448
  }
423 449

  
424 450
  # when saving income_accno_id or expense_accno_id use ids from the selected
......
443 469
  }
444 470

  
445 471
  $entry->{object}->part_type($part_type);
472
  $entry->{object}->classification_id( $classification_id );
446 473

  
447 474
  return 1;
448 475
}
......
699 726

  
700 727
  $self->add_displayable_columns({ name => 'bin_id',             description => $::locale->text('Bin (database ID)')                                    },
701 728
                                 { name => 'bin',                description => $::locale->text('Bin (name)')                                           },
702
                                 { name => 'buchungsgruppen_id', description => $::locale->text('Booking group (database ID)')                         },
703
                                 { name => 'buchungsgruppe',     description => $::locale->text('Booking group (name)')                                },
729
                                 { name => 'buchungsgruppen_id', description => $::locale->text('Booking group (database ID)')                          },
730
                                 { name => 'buchungsgruppe',     description => $::locale->text('Booking group (name)')                                 },
704 731
                                 { name => 'description',        description => $::locale->text('Description')                                          },
705 732
                                 { name => 'drawing',            description => $::locale->text('Drawing')                                              },
706 733
                                 { name => 'ean',                description => $::locale->text('EAN')                                                  },
......
721 748
                                 { name => 'partnumber',         description => $::locale->text('Part Number')                                          },
722 749
                                 { name => 'partsgroup_id',      description => $::locale->text('Partsgroup (database ID)')                             },
723 750
                                 { name => 'partsgroup',         description => $::locale->text('Partsgroup (name)')                                    },
751
                                 { name => 'classification_by',  description => $::locale->text('Article classification')  . ' [3]'                     },
724 752
                                 { name => 'payment_id',         description => $::locale->text('Payment terms (database ID)')                          },
725 753
                                 { name => 'payment',            description => $::locale->text('Payment terms (name)')                                 },
726 754
                                 { name => 'price_factor_id',    description => $::locale->text('Price factor (database ID)')                           },
727 755
                                 { name => 'price_factor',       description => $::locale->text('Price factor (name)')                                  },
728 756
                                 { name => 'rop',                description => $::locale->text('ROP')                                                  },
729 757
                                 { name => 'sellprice',          description => $::locale->text('Sellprice')                                            },
730
                                 { name => 'shop',               description => $::locale->text('Shop article')                                          },
731
                                 { name => 'type',               description => $::locale->text('Article type')  . ' [3]'                             },
758
                                 { name => 'shop',               description => $::locale->text('Shop article')                                         },
759
                                 { name => 'type',               description => $::locale->text('Article type')  . ' [3]'                               },
732 760
                                 { name => 'unit',               description => $::locale->text('Unit (if missing or empty default unit will be used)') },
733 761
                                 { name => 've',                 description => $::locale->text('Verrechnungseinheit')                                  },
734 762
                                 { name => 'warehouse_id',       description => $::locale->text('Warehouse (database ID)')                              },
735
                                 { name => 'warehouse',          description => $::locale->text('Warehouse (name)')                              },
763
                                 { name => 'warehouse',          description => $::locale->text('Warehouse (name)')                                     },
736 764
                                 { name => 'weight',             description => $::locale->text('Weight')                                               },
737 765
                                );
738 766

  
SL/Controller/PartsClassification.pm
1
package SL::Controller::PartsClassification;
2

  
3
use strict;
4

  
5
use parent qw(SL::Controller::Base);
6

  
7
use SL::DB::PartsClassification;
8
use SL::Helper::Flash;
9

  
10
use Rose::Object::MakeMethods::Generic
11
(
12
 scalar => [ qw(parts_classification) ],
13
);
14

  
15
__PACKAGE__->run_before('check_auth');
16
__PACKAGE__->run_before('load_parts_classification', only => [ qw(edit update destroy) ]);
17

  
18
#
19
# actions
20
#
21

  
22
sub action_list {
23
  my ($self) = @_;
24

  
25
  $self->render('parts_classification/list',
26
                title         => $::locale->text('Parts Classifications'),
27
                PARTS_CLASSIFICATIONS => SL::DB::Manager::PartsClassification->get_all_sorted);
28
}
29

  
30
sub action_new {
31
  my ($self) = @_;
32

  
33
  $self->{parts_classification} = SL::DB::PartsClassification->new;
34
  $self->render('parts_classification/form', title => $::locale->text('Create a new parts classification'));
35
}
36

  
37
sub action_edit {
38
  my ($self) = @_;
39
  $self->render('parts_classification/form', title => $::locale->text('Edit parts classification'));
40
}
41

  
42
sub action_create {
43
  my ($self) = @_;
44

  
45
  $self->{parts_classification} = SL::DB::PartsClassification->new;
46
  $self->create_or_update;
47
}
48

  
49
sub action_update {
50
  my ($self) = @_;
51
  $self->create_or_update;
52
}
53

  
54
sub action_destroy {
55
  my ($self) = @_;
56

  
57
  if ( $self->{parts_classification}->id < 5 ) {
58
    flash_later('error', $::locale->text('The basic parts classification cannot be deleted.'));
59
  }
60
  elsif (eval { $self->{parts_classification}->delete; 1; }) {
61
    flash_later('info',  $::locale->text('The parts classification has been deleted.'));
62
  } else {
63
    flash_later('error', $::locale->text('The parts classification is in use and cannot be deleted.'));
64
  }
65

  
66
  $self->redirect_to(action => 'list');
67
}
68

  
69
sub action_reorder {
70
  my ($self) = @_;
71

  
72
  SL::DB::PartsClassification->reorder_list(@{ $::form->{parts_classification_id} || [] });
73

  
74
  $self->render(\'', { type => 'json' });
75
}
76

  
77
#
78
# filters
79
#
80

  
81
sub check_auth {
82
  $::auth->assert('config');
83
}
84

  
85
#
86
# helpers
87
#
88

  
89
sub create_or_update {
90
  my $self   = shift;
91
  my $is_new = !$self->{parts_classification}->id;
92
  my $params = delete($::form->{parts_classification}) || { };
93

  
94
  $self->{parts_classification}->assign_attributes(%{ $params });
95

  
96
  my @errors = $self->{parts_classification}->validate;
97

  
98
  if (@errors) {
99
    flash('error', @errors);
100
    $self->render('parts_classification/form', title => $is_new ? $::locale->text('Create a new parts classification') : $::locale->text('Edit parts classification'));
101
    return;
102
  }
103

  
104
  $self->{parts_classification}->save;
105

  
106
  flash_later('info', $is_new ? $::locale->text('The parts classification has been created.') : $::locale->text('The parts classification has been saved.'));
107
  $self->redirect_to(action => 'list');
108
}
109

  
110
sub load_parts_classification {
111
  my ($self) = @_;
112
  $self->{parts_classification} = SL::DB::PartsClassification->new(id => $::form->{id})->load;
113
}
114

  
115
1;
SL/DB/Helper/Mappings.pm
153 153
  oe                             => 'order',
154 154
  parts                          => 'part',
155 155
  partsgroup                     => 'parts_group',
156
  parts_classifications          => 'PartsClassification',
156 157
  parts_price_history            => 'PartsPriceHistory',
157 158
  payment_terms                  => 'payment_term',
158 159
  periodic_invoices              => 'periodic_invoice',
SL/DB/Manager/PartsClassification.pm
1
# This file has been auto-generated only because it didn't exist.
2
# Feel free to modify it at will; it will not be overwritten automatically.
3

  
4
package SL::DB::Manager::PartsClassification;
5

  
6
use strict;
7

  
8
use parent qw(SL::DB::Helper::Manager);
9
use SL::DB::Helper::Sorted;
10

  
11
sub object_class { 'SL::DB::PartsClassification' }
12

  
13
__PACKAGE__->make_manager_methods;
14

  
15

  
16
sub get_abbreviation {
17
  my ($class,$id) = @_;
18
  my $obj = $class->get_first(query => [ id => $id ]);
19
  return $obj->abbreviation?$obj->abbreviation:undef;
20
}
21

  
22
1;
SL/DB/MetaSetup/Part.pm
12 12
  bin_id             => { type => 'integer' },
13 13
  bom                => { type => 'boolean', default => 'false' },
14 14
  buchungsgruppen_id => { type => 'integer' },
15
  classification_id  => { type => 'integer', default => '0' },
15 16
  description        => { type => 'text' },
16 17
  drawing            => { type => 'text' },
17 18
  ean                => { type => 'text' },
......
63 64
    key_columns => { buchungsgruppen_id => 'id' },
64 65
  },
65 66

  
67
  classification => {
68
    class       => 'SL::DB::PartsClassification',
69
    key_columns => { classification_id => 'id' },
70
  },
71

  
66 72
  partsgroup => {
67 73
    class       => 'SL::DB::PartsGroup',
68 74
    key_columns => { partsgroup_id => 'id' },
SL/DB/MetaSetup/PartsClassification.pm
1
# This file has been auto-generated. Do not modify it; it will be overwritten
2
# by rose_auto_create_model.pl automatically.
3
package SL::DB::PartsClassification;
4

  
5
use strict;
6

  
7
use parent qw(SL::DB::Object);
8

  
9
__PACKAGE__->meta->table('parts_classifications');
10

  
11
__PACKAGE__->meta->columns(
12
  abbreviation      => { type => 'text' },
13
  description       => { type => 'text' },
14
  id                => { type => 'serial', not_null => 1 },
15
  used_for_purchase => { type => 'boolean', default => 'true' },
16
  used_for_sale     => { type => 'boolean', default => 'true' },
17
);
18

  
19
__PACKAGE__->meta->primary_key_columns([ 'id' ]);
20

  
21
1;
22
;
SL/DB/PartsClassification.pm
1
# This file has been auto-generated only because it didn't exist.
2
# Feel free to modify it at will; it will not be overwritten automatically.
3

  
4
package SL::DB::PartsClassification;
5

  
6
use strict;
7

  
8
use SL::DB::MetaSetup::PartsClassification;
9
use SL::DB::Manager::PartsClassification;
10

  
11
__PACKAGE__->meta->initialize;
12

  
13
sub validate {
14
  my ($self) = @_;
15

  
16
  my @errors;
17
  push @errors, $::locale->text('The description is missing.')  if !$self->description;
18
  push @errors, $::locale->text('The abbreviation is missing.') if !$self->abbreviation;
19

  
20
  return @errors;
21
}
22

  
23

  
24
1;
SL/IC.pm
85 85
    # retrieve assembly items
86 86
    $query =
87 87
      qq|SELECT p.id, p.partnumber, p.description,
88
           p.classification_id,
88 89
           p.sellprice, p.lastcost, p.weight, a.qty, a.bom, p.unit,
89 90
           pg.partsgroup, p.price_factor_id, pfac.factor AS price_factor
90 91
         FROM parts p
......
101 102
      foreach my $key (keys %{$ref}) {
102 103
        $form->{"${key}_$form->{assembly_rows}"} = $ref->{$key};
103 104
      }
105
      $form->{"type_and_classific_$form->{assembly_rows}"} = $::request->presenter->type_abbreviation($ref->{part_type}).
106
                                                             $::request->presenter->classification_abbreviation($ref->{classification_id});
104 107
    }
105 108
    $sth->finish;
106 109

  
......
334 337
         partnumber = ?,
335 338
         description = ?,
336 339
         makemodel = ?,
340
         classification_id = ?,
337 341
         listprice = ?,
338 342
         sellprice = ?,
339 343
         lastcost = ?,
......
367 371
  @values = ($form->{partnumber},
368 372
             $form->{description},
369 373
             $makemodel ? 't' : 'f',
374
             $form->{classification_id},
370 375
             $form->{listprice},
371 376
             $form->{sellprice},
372 377
             $form->{lastcost},
......
642 647

  
643 648
  my $query =
644 649
    qq|SELECT p.id, p.partnumber, p.description, p.sellprice,
650
       p.classification_id,
645 651
       p.weight, p.onhand, p.unit, pg.partsgroup, p.lastcost,
646 652
       p.price_factor_id, pfac.factor AS price_factor, p.notes as longdescription
647 653
       FROM parts p
......
723 729
#  my @other_flags          = qw(onhand); # ToDO: implement these
724 730
#  my @inactive_flags       = qw(l_subtotal short l_linetotal);
725 731

  
726
  my @select_tokens = qw(id factor);
732
  my @select_tokens = qw(id factor part_type classification_id);
727 733
  my @where_tokens  = qw(1=1);
728 734
  my @group_tokens  = ();
729 735
  my @bind_vars     = ();
......
800 806
    insertdate         => 'itime::DATE',
801 807
  );
802 808

  
803
  if (($form->{searchitems} eq 'assembly') && $form->{l_lastcost}) {
809
  if ($form->{l_assembly} && $form->{l_lastcost}) {
804 810
    @simple_l_switches = grep { $_ ne 'lastcost' } @simple_l_switches;
805 811
  }
806 812

  
......
890 896
    push @select_tokens, $_;
891 897
  }
892 898

  
893
  for ($form->{searchitems}) {
894
    push @where_tokens, "p.part_type = 'part'"     if /part/;
895
    push @where_tokens, "p.part_type = 'service'"  if /service/;
896
    push @where_tokens, "p.part_type = 'assembly'" if /assembly/;
899
  # Oder Bedingungen fuer Ware Dienstleistung Erzeugnis:
900
  if ($form->{l_part} || $form->{l_assembly} || $form->{l_service}) {
901
      my @or_tokens = ();
902
      push @or_tokens, "p.part_type = 'service'"  if $form->{l_service};
903
      push @or_tokens, "p.part_type = 'assembly'" if $form->{l_assembly};
904
      push @or_tokens, "p.part_type = 'part'"     if $form->{l_part};
905
      push @where_tokens, join ' OR ', map { "($_)" } @or_tokens;
906
  }
907
  else {
908
      # gar keine Teile
909
      push @where_tokens, q|'F' = 'T'|;
910
  }
911

  
912
  if ( $form->{classification_id} > 0 ) {
913
    push @where_tokens, "p.classification_id = ?";
914
    push @bind_vars, $form->{classification_id};
897 915
  }
898 916

  
899 917
  for ($form->{itemstatus}) {
......
951 969

  
952 970
  push @select_tokens, @qsooqr_flags, 'quotation', 'cv', 'ioi.id', 'ioi.ioi'  if $bsooqr;
953 971
  push @select_tokens, @deliverydate_flags                                    if $bsooqr && $form->{l_deliverydate};
954
  push @select_tokens, $q_assembly_lastcost                                   if ($form->{searchitems} eq 'assembly') && $form->{l_lastcost};
972
  push @select_tokens, $q_assembly_lastcost                                   if $form->{l_assembly} && $form->{l_lastcost};
955 973
  push @bsooqr_tokens, q|module = 'ir' AND NOT ioi.assemblyitem|              if $form->{bought};
956 974
  push @bsooqr_tokens, q|module = 'is' AND NOT ioi.assemblyitem|              if $form->{sold};
957 975
  push @bsooqr_tokens, q|module = 'oe' AND NOT quotation AND cv = 'customer'| if $form->{ordered};
......
1049 1067
  # post processing for assembly parts lists (bom)
1050 1068
  # for each part get the assembly parts and add them into the partlist.
1051 1069
  my @assemblies;
1052
  if ($form->{searchitems} eq 'assembly' && $form->{bom}) {
1070
  if ($form->{l_assembly} && $form->{bom}) {
1053 1071
    $query =
1054 1072
      qq|SELECT p.id, p.partnumber, p.description, a.qty AS onhand,
1055 1073
           p.unit, p.notes, p.itime::DATE as insertdate,
......
1079 1097
    $form->{parts} = \@assemblies;
1080 1098
  }
1081 1099

  
1082
  if ($form->{l_pricegroups} ) {
1100
  if ($form->{l_pricegroups} && SL::DB::Manager::Price->get_all_count() > 0 ) {
1083 1101
    my $query = <<SQL;
1084 1102
       SELECT parts_id, price, pricegroup_id
1085 1103
       FROM prices
......
1096 1114
      }
1097 1115
      $sth->finish;
1098 1116
    }
1099
  };
1100

  
1117
  }
1101 1118

  
1102 1119
  $main::lxdebug->leave_sub();
1103 1120

  
......
1393 1410
  }
1394 1411

  
1395 1412
  my $query =
1396
    qq|SELECT id, partnumber, description, unit, sellprice
1413
    qq|SELECT id, partnumber, description, unit, sellprice,
1414
       classification_id
1397 1415
       FROM parts
1398 1416
       WHERE $where ORDER BY $order|;
1399 1417

  
......
1406 1424
    }
1407 1425

  
1408 1426
    $j++;
1427
    $form->{"type_and_classific_$j"} = $::request->presenter->type_abbreviation($ref->{part_type}).
1428
                                       $::request->presenter->classification_abbreviation($ref->{classification_id});
1409 1429
    $form->{"id_$j"}          = $ref->{id};
1410 1430
    $form->{"partnumber_$j"}  = $ref->{partnumber};
1411 1431
    $form->{"description_$j"} = $ref->{description};
......
1733 1753
  for my $i (1..$rowcount) {
1734 1754
    my $id = $form->{"${prefix}${i}"};
1735 1755
    next unless $id;
1736

  
1737
    push @{ $template_arrays{part_type} },  $parts_by_id{$id}->type;
1756
    my $prt = $parts_by_id{$id};
1757
    my $type_abbr = $::request->presenter->type_abbreviation($prt->part_type);
1758
    push @{ $template_arrays{part_type} }, $type_abbr;
1759
    push @{ $template_arrays{type_and_classific}},  $type_abbr.$::request->presenter->classification_abbreviation($prt->classification_id);
1738 1760
  }
1739 1761

  
1740
  return %template_arrays;
1741 1762
  $main::lxdebug->leave_sub();
1763
  return %template_arrays;
1742 1764
}
1743 1765

  
1744 1766
sub normalize_text_blocks {
......
1760 1782
   $main::lxdebug->leave_sub();
1761 1783
}
1762 1784

  
1763

  
1764 1785
1;
SL/IR.pm
1020 1020
        i.description, i.longdescription, i.qty, i.fxsellprice AS sellprice, i.parts_id AS id, i.unit, i.deliverydate, i.project_id, i.serialnumber,
1021 1021
        i.price_factor_id, i.price_factor, i.marge_price_factor, i.discount, i.active_price_source, i.active_discount_source,
1022 1022
        p.partnumber, p.part_type, pr.projectnumber, pg.partsgroup
1023
        ,p.classification_id
1023 1024

  
1024 1025
        FROM invoice i
1025 1026
        JOIN parts p ON (i.parts_id = p.id)
......
1279 1280
         p.notes AS partnotes, p.notes AS longdescription, p.not_discountable,
1280 1281
         p.inventory_accno_id, p.price_factor_id,
1281 1282
         p.ean,
1283
         p.classification_id,
1282 1284

  
1283 1285
         pfac.factor AS price_factor,
1284 1286

  
......
1294 1296
         c3.new_chart_id                  AS expense_new_chart,
1295 1297
         date($transdate) - c3.valid_from AS expense_valid,
1296 1298

  
1299
         pt.used_for_purchase AS used_for_purchase,
1297 1300
         pg.partsgroup
1298 1301

  
1299 1302
       FROM parts p
......
1310 1313
           FROM taxzone_charts tc
1311 1314
           WHERE tc.taxzone_id = '$taxzone_id' and tc.buchungsgruppen_id = p.buchungsgruppen_id) = c3.id)
1312 1315
       LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
1316
       LEFT JOIN parts_classifications pt ON (pt.id = p.classification_id)
1313 1317
       LEFT JOIN price_factors pfac ON (pfac.id = p.price_factor_id)
1314 1318
       WHERE $where|;
1315 1319
  my $sth = prepare_execute_query($form, $dbh, $query, @values);
......
1328 1332
  map { push @{ $_ }, prepare_query($form, $dbh, $_->[0]) } @translation_queries;
1329 1333

  
1330 1334
  $form->{item_list} = [];
1335
  my $has_wrong_pclass = 0;
1331 1336
  while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
1332 1337

  
1333 1338
    if ($mm_by_id{$ref->{id}}) {
......
1338 1343
    if (($::form->{"partnumber_$i"} ne '') && ($ref->{ean} eq $::form->{"partnumber_$i"})) {
1339 1344
      push @{ $ref->{matches} ||= [] }, $::locale->text('EAN') . ': ' . $ref->{ean};
1340 1345
    }
1346
    $ref->{type_and_classific} = $::request->presenter->type_abbreviation($ref->{part_type}).
1347
                                 $::request->presenter->classification_abbreviation($ref->{classification_id});
1341 1348

  
1349
    if (! $ref->{used_for_purchase} ) {
1350
       $has_wrong_pclass = 2;
1351
       next;
1352
    }
1342 1353
    # In der Buchungsgruppe ist immer ein Bestandskonto verknuepft, auch wenn
1343 1354
    # es sich um eine Dienstleistung handelt. Bei Dienstleistungen muss das
1344 1355
    # Buchungskonto also aus dem Ergebnis rausgenommen werden.
......
1408 1419
  $sth->finish();
1409 1420
  $_->[1]->finish for @translation_queries;
1410 1421

  
1422
  $form->{is_wrong_pclass} = $has_wrong_pclass;
1411 1423
  foreach my $item (@{ $form->{item_list} }) {
1412 1424
    my $custom_variables = CVar->get_custom_variables(module   => 'IC',
1413 1425
                                                      trans_id => $item->{id},
1414 1426
                                                      dbh      => $dbh,
1415 1427
                                                     );
1416

  
1428
    $form->{is_wrong_pclass} = 0; # one correct type
1417 1429
    map { $item->{"ic_cvar_" . $_->{name} } = $_->{value} } @{ $custom_variables };
1418 1430
  }
1419 1431

  
SL/IS.pm
2003 2003
           i.project_id, i.serialnumber, i.pricegroup_id, i.ordnumber, i.donumber, i.transdate, i.cusordnumber, i.subtotal, i.lastcost,
2004 2004
           i.price_factor_id, i.price_factor, i.marge_price_factor, i.active_price_source, i.active_discount_source,
2005 2005
           p.partnumber, p.part_type, p.notes AS partnotes, p.formel, p.listprice,
2006
           p.classification_id,
2006 2007
           pr.projectnumber, pg.partsgroup, prg.pricegroup
2007 2008

  
2008 2009
         FROM invoice i
......
2300 2301
         p.id, p.partnumber, p.description, p.sellprice,
2301 2302
         p.listprice, p.part_type, p.lastcost,
2302 2303
         p.ean, p.notes,
2304
         p.classification_id,
2303 2305

  
2304 2306
         c1.accno AS inventory_accno,
2305 2307
         c1.new_chart_id AS inventory_new_chart,
......
2319 2321
         p.price_factor_id, p.weight,
2320 2322

  
2321 2323
         pfac.factor AS price_factor,
2322

  
2324
         pt.used_for_sale AS used_for_sale,
2323 2325
         pg.partsgroup
2324 2326

  
2325 2327
       FROM parts p
......
2336 2338
           FROM taxzone_charts tc
2337 2339
           WHERE tc.buchungsgruppen_id = p.buchungsgruppen_id and tc.taxzone_id = ${taxzone_id}) = c3.id)
2338 2340
       LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
2341
       LEFT JOIN parts_classifications pt ON (pt.id = p.classification_id)
2339 2342
       LEFT JOIN price_factors pfac ON (pfac.id = p.price_factor_id)
2340 2343
       WHERE $where|;
2341 2344
  my $sth = prepare_execute_query($form, $dbh, $query, @values);
......
2353 2356
                                   LIMIT 1| ] );
2354 2357
  map { push @{ $_ }, prepare_query($form, $dbh, $_->[0]) } @translation_queries;
2355 2358

  
2359
  my $has_wrong_pclass = 0;
2356 2360
  while (my $ref = $sth->fetchrow_hashref('NAME_lc')) {
2357 2361

  
2358 2362
    if ($mm_by_id{$ref->{id}}) {
......
2364 2368
      push @{ $ref->{matches} ||= [] }, $::locale->text('EAN') . ': ' . $ref->{ean};
2365 2369
    }
2366 2370

  
2371
    $ref->{type_and_classific} = $::request->presenter->type_abbreviation($ref->{part_type}).
2372
                                 $::request->presenter->classification_abbreviation($ref->{classification_id});
2373
    if (! $ref->{used_for_sale} ) {
2374
        $has_wrong_pclass = 1;
2375
        next;
2376
    }
2367 2377
    # In der Buchungsgruppe ist immer ein Bestandskonto verknuepft, auch wenn
2368 2378
    # es sich um eine Dienstleistung handelt. Bei Dienstleistungen muss das
2369 2379
    # Buchungskonto also aus dem Ergebnis rausgenommen werden.
......
2447 2457
  $sth->finish;
2448 2458
  $_->[1]->finish for @translation_queries;
2449 2459

  
2460
  $form->{is_wrong_pclass} = $has_wrong_pclass;
2450 2461
  foreach my $item (@{ $form->{item_list} }) {
2451 2462
    my $custom_variables = CVar->get_custom_variables(module   => 'IC',
2452 2463
                                                      trans_id => $item->{id},
2453 2464
                                                      dbh      => $dbh,
2454 2465
                                                     );
2455

  
2466
    $form->{is_wrong_pclass} = 0; # one correct type
2456 2467
    map { $item->{"ic_cvar_" . $_->{name} } = $_->{value} } @{ $custom_variables };
2457 2468
  }
2458

  
2459 2469
  $main::lxdebug->leave_sub();
2460 2470
}
2461 2471

  
SL/OE.pm
1094 1094
           c3.accno AS expense_accno,   c3.new_chart_id AS expense_new_chart,   date($transdate) - c3.valid_from as expense_valid,
1095 1095
           oe.ordnumber AS ordnumber_oe, oe.transdate AS transdate_oe, oe.cusordnumber AS cusordnumber_oe,
1096 1096
           p.partnumber, p.part_type, p.listprice, o.description, o.qty,
1097
           p.classification_id,
1097 1098
           o.sellprice, o.parts_id AS id, o.unit, o.discount, p.notes AS partnotes, p.part_type,
1098 1099
           o.reqdate, o.project_id, o.serialnumber, o.ship, o.lastcost,
1099 1100
           o.ordnumber, o.transdate, o.cusordnumber, o.subtotal, o.longdescription,
SL/Presenter/Part.pm
3 3
use strict;
4 4

  
5 5
use SL::DB::Part;
6
use SL::DB::Manager::PartsClassification;
6 7

  
7 8
use Exporter qw(import);
8
our @EXPORT = qw(part_picker part);
9
our @EXPORT = qw(part_picker part select_classification classification_abbreviation type_abbreviation type_and_classification);
9 10

  
10 11
use Carp;
11 12

  
......
46 47
  $self->html_tag('span', $ret, class => 'part_picker');
47 48
}
48 49

  
50
#
51
# Must be addapted to new type table
52
#
53
sub type_abbreviation {
54
  my ($self, $part_type) = @_;
55
  $main::lxdebug->message(LXDebug->DEBUG2(),"parttype=".$part_type);
56
  return $::locale->text('Assembly (typeabbreviation)')   if $part_type eq 'assembly';
57
  return $::locale->text('Part (typeabbreviation)')       if $part_type eq 'part';
58
  return $::locale->text('Assortment (typeabbreviation)') if $part_type eq 'assortment';
59
  return $::locale->text('Service (typeabbreviation)');
60
}
61

  
62
#
63
# Translations for Abbreviations:
64
#
65
# $::locale->text('None (typeabbreviation)')
66
# $::locale->text('Purchase (typeabbreviation)')
67
# $::locale->text('Sales (typeabbreviation)')
68
# $::locale->text('Merchandise (typeabbreviation)')
69
# $::locale->text('Production (typeabbreviation)')
70
#
71
# and for descriptions
72
# $::locale->text('Purchase')
73
# $::locale->text('Sales')
74
# $::locale->text('Merchandise')
75
# $::locale->text('Production')
76

  
77
sub classification_abbreviation {
78
  my ($self, $id) = @_;
79
  $main::lxdebug->message(LXDebug->DEBUG2(),"classif=".$id);
80
  return $::locale->text(SL::DB::Manager::PartsClassification->get_abbreviation($id));
81
}
82

  
83
sub select_classification {
84
  my ($self, $name, %attributes) = @_;
85
  $attributes{value_key} = 'id';
86
  $attributes{title_key} = 'description';
87
  my $collection = SL::DB::Manager::PartsClassification->get_all_sorted();
88
  $_->description($::locale->text($_->description)) for @{ $collection };
89
  return $self->select_tag( $name, $collection, %attributes );
90
}
91

  
49 92
1;
50 93

  
51 94
__END__
SL/WH.pm
368 368
    push @filter_vars, like($filter{description});
369 369
  }
370 370

  
371
  if ($filter{classification_id}) {
372
    push @filter_ary, "p.classification_id = ?";
373
    push @filter_vars, $filter{classification_id};
374
  }
375

  
371 376
  if ($filter{chargenumber}) {
372 377
    push @filter_ary, "i1.chargenumber ILIKE ?";
373 378
    push @filter_vars, like($filter{chargenumber});
......
426 431
     "qty"                  => "ABS(SUM(i1.qty))",
427 432
     "partnumber"           => "p.partnumber",
428 433
     "partdescription"      => "p.description",
434
     "classification_id"    => "p.classification_id",
435
     "assembly"             => "p.assembly",
436
     "inventory_accno_id"   => "p.inventory_accno_id",
429 437
     "bindescription"       => "b.description",
430 438
     "chargenumber"         => "i1.chargenumber",
431 439
     "bestbefore"           => "i1.bestbefore",
......
457 465
     "warehouse_from"       => "'$filter{na}'",
458 466
     };
459 467

  
468
  $form->{l_classification_id}  = 'Y';
469
  $form->{l_assembly}           = 'Y';
470
  $form->{l_inventory_accno_id} = 'Y';
460 471
  $form->{l_invoice_id} = $form->{l_oe_id} if $form->{l_oe_id};
461 472

  
462 473
  # build the select clauses.
......
614 625
#  - warehouse_id - will return matches with this warehouse_id only
615 626
#  - partnumber   - will return only matches where the given string is a substring of the partnumber
616 627
#  - partsid      - will return matches with this parts_id only
628
#  - classification_id - will return matches with this parts with this classification only
617 629
#  - description  - will return only matches where the given string is a substring of the description
618 630
#  - chargenumber - will return only matches where the given string is a substring of the chargenumber
619 631
#  - bestbefore   - will return only matches with this bestbefore date
......
665 677
    push @filter_vars, like($filter{partnumber});
666 678
  }
667 679

  
680
  if ($filter{classification_id}) {
681
    push @filter_ary, "p.classification_id = ?";
682
    push @filter_vars, $filter{classification_id};
683
  }
684

  
668 685
  if ($filter{description}) {
669 686
    push @filter_ary,  "p.description ILIKE ?";
670 687
    push @filter_vars, like($filter{description});
......
737 754
     "warehouseid"          => "i.warehouse_id",
738 755
     "partnumber"           => "p.partnumber",
739 756
     "partdescription"      => "p.description",
757
     "classification_id"    => "p.classification_id",
758
     "assembly"             => "p.assembly",
759
     "inventory_accno_id"   => "p.inventory_accno_id",
740 760
     "bindescription"       => "b.description",
741 761
     "binid"                => "b.id",
742 762
     "chargenumber"         => "i.chargenumber",
......
747 767
     "partunit"             => "p.unit",
748 768
     "stock_value"          => "p.lastcost / COALESCE(pfac.factor, 1)",
749 769
  );
770
  $form->{l_classification_id}  = 'Y';
771
  $form->{l_assembly}           = 'Y';
772
  $form->{l_inventory_accno_id} = 'Y';
750 773
  my $select_clause = join ', ', map { +/^l_/; "$select_tokens{$'} AS $'" }
751 774
        ( grep( { !/qty/ and /^l_/ and $form->{$_} eq 'Y' } keys %$form),
752 775
          qw(l_parts_id l_qty l_partunit) );
bin/mozilla/ic.pl
100 100
  $form->{lastsort}     = ""; # memory for which table was sort at last time
101 101
  $form->{ndxs_counter} = 0;  # counter for added entries to top100
102 102

  
103
  my %is_xyz     = map { +"is_$_" => ($form->{searchitems} eq $_) } qw(part service assembly);
103
  # for seach all possibibilities, is_service only used as UNLESS so == 0
104
  my %is_xyz     = ("is_part" => 1, "is_service" => 0, "is_assembly" =>1 );
104 105

  
105 106
  $form->{title} = (ucfirst $form->{searchitems}) . "s";
107
  $form->{title} =~ s/ys$/ies/;
106 108
  $form->{title} = $locale->text($form->{title});
107
  $form->{title} = $locale->text('Assemblies') if ($is_xyz{is_assembly});
108 109

  
109 110
  $form->{CUSTOM_VARIABLES}                  = CVar->get_configs('module' => 'IC');
110 111
  ($form->{CUSTOM_VARIABLES_FILTER_CODE},
......
233 234
#  searchitems=part revers=0 lastsort=''
234 235
#
235 236
# filter:
236
# partnumber ean description partsgroup serialnumber make model drawing microfiche
237
# partnumber ean description partsgroup classification serialnumber make model drawing microfiche
237 238
# transdatefrom transdateto
238 239
#
239 240
# radio:
......
300 301
    'unit'               => { 'text' => $locale->text('Unit'), },
301 302
    'weight'             => { 'text' => $locale->text('Weight'), },
302 303
    'shop'               => { 'text' => $locale->text('Shop article'), },
304
    'type_and_classific' => { 'text' => $locale->text('Type'), },
303 305
    'projectnumber'      => { 'text' => $locale->text('Project Number'), },
304 306
    'projectdescription' => { 'text' => $locale->text('Project Description'), },
305 307
  );
......
424 426
    $form->{l_linetotallastcost}  = $form->{searchitems} eq 'assembly' && !$form->{bom} ? "" : 'Y' if  $form->{l_lastcost};
425 427
    $form->{l_linetotallistprice} = "Y" if $form->{l_listprice};
426 428
  }
429
  $form->{"l_type_and_classific"} = "Y";
427 430

  
428
  if ($form->{searchitems} eq 'service') {
431
   if ($form->{l_service} && !$form->{l_assembly} && !$form->{l_part}) {
429 432

  
430 433
    # remove bin, weight and rop from list
431 434
    map { $form->{"l_$_"} = "" } qw(bin weight rop);
......
472 475
  IC->all_parts(\%myconfig, \%$form);
473 476

  
474 477
  my @columns = qw(
475
    partnumber description notes partsgroup bin onhand rop soldtotal unit listprice
478
    partnumber type_and_classific description notes partsgroup bin onhand rop soldtotal unit listprice
476 479
    linetotallistprice sellprice linetotalsellprice lastcost linetotallastcost
477 480
    priceupdate weight image drawing microfiche invnumber ordnumber quonumber
478 481
    transdate name serialnumber deliverydate ean projectnumber projectdescription
......
505 508

  
506 509
  my @hidden_variables = (
507 510
    qw(l_subtotal l_linetotal searchitems itemstatus bom l_pricegroups insertdatefrom insertdateto),
511
    qw(l_type_and_classific classification_id),
508 512
    @itemstatus_keys,
509 513
    @callback_keys,
510 514
    map({ "cvar_$_->{name}" } @searchable_custom_variables),
......
531 535
    'part'     => $locale->text('part_list'),
532 536
    'service'  => $locale->text('service_list'),
533 537
    'assembly' => $locale->text('assembly_list'),
538
    'article'  => $locale->text('article_list'),
534 539
  );
535 540

  
536 541
  $report->set_options('raw_top_info_text'     => $form->parse_html_template('ic/generate_report_top', { options => \@options }),
537 542
                       'raw_bottom_info_text'  => $form->parse_html_template('ic/generate_report_bottom'),
538 543
                       'output_format'         => 'HTML',
539 544
                       'title'                 => $form->{title},
540
                       'attachment_basename'   => $attachment_basenames{$form->{searchitems}} . strftime('_%Y%m%d', localtime time),
545
                       'attachment_basename'   => 'article_list' . strftime('_%Y%m%d', localtime time),
541 546
  );
542 547
  $report->set_options_from_form();
543 548
  $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
......
647 652
    map { $row->{$_}{link} = $ref->{$_} } qw(drawing microfiche);
648 653

  
649 654
    $row->{notes}{data} = SL::HTML::Util->strip($ref->{notes});
655
    $row->{type_and_classific}{data} = $::request->presenter->type_abbreviation($ref->{part_type}).
656
                                       $::request->presenter->classification_abbreviation($ref->{classification_id});
650 657

  
651 658
    $report->add_data($row);
652 659

  
......
658 665
         (!$next_ref->{assemblyitem} && ($same_item ne $next_ref->{ $form->{sort} })))) {
659 666
      my $row = { map { $_ => { 'class' => 'listsubtotal', } } @columns };
660 667

  
661
      if (($form->{searchitems} ne 'assembly') || !$form->{bom}) {
668
      if ( !$form->{l_assembly} || !$form->{bom}) {
662 669
        $row->{soldtotal}->{data} = $form->format_amount(\%myconfig, $subtotals{soldtotal});
663 670
      }
664 671

  
......
696 703
  my ($column_index, $subtotalonhand, $subtotalsellprice, $subtotallastcost, $subtotallistprice) = @_;
697 704

  
698 705
  map { $column_data{$_} = "<td>&nbsp;</td>" } @{ $column_index };
699
  $$subtotalonhand = 0 if ($form->{searchitems} eq 'assembly' && $form->{bom});
706
  $$subtotalonhand = 0 if ($form->{l_assembly} && $form->{bom});
700 707

  
701 708
  $column_data{onhand} =
702 709
      "<th class=listsubtotal align=right>"
......
938 945
  my (@column_index);
939 946
  my ($nochange, $callback, $previousform, $linetotal, $line_purchase_price, $href);
940 947

  
941
  @column_index = qw(runningnumber qty unit bom partnumber description partsgroup lastcost total);
948
  @column_index = qw(runningnumber qty unit bom partnumber type_and_classific description partsgroup lastcost total);
942 949

  
943 950
  if ($form->{previousform}) {
944 951
    $nochange     = 1;
945
    @column_index = qw(qty unit bom partnumber description partsgroup total);
952
    @column_index = qw(qty unit bom partnumber type_and_classific description partsgroup total);
946 953
  } else {
947 954

  
948 955
    # change callback
......
965 972
  }
966 973

  
967 974
  my %header = (
968
   runningnumber => { text =>  $locale->text('No.'),              nowrap => 1, width => '5%',  align => 'left',},
969
   qty           => { text =>  $locale->text('Qty'),              nowrap => 1, width => '10%', align => 'left',},
970
   unit          => { text =>  $locale->text('Unit'),             nowrap => 1, width => '5%',  align => 'left',},
971
   partnumber    => { text =>  $locale->text('Part Number'),      nowrap => 1, width => '20%', align => 'left',},
972
   description   => { text =>  $locale->text('Part Description'), nowrap => 1, width => '50%', align => 'left',},
973
   lastcost      => { text =>  $locale->text('Purchase Prices'),  nowrap => 1, width => '50%', align => 'right',},
974
   total         => { text =>  $locale->text('Sale Prices'),      nowrap => 1,                 align => 'right',},
975
   bom           => { text =>  $locale->text('BOM'),                                           align => 'center',},
976
   partsgroup    => { text =>  $locale->text('Group'),                                         align => 'left',},
975
   runningnumber      => { text =>  $locale->text('No.'),              nowrap => 1, width => '5%',  align => 'left',},
976
   qty                => { text =>  $locale->text('Qty'),              nowrap => 1, width => '10%', align => 'left',},
977
   unit               => { text =>  $locale->text('Unit'),             nowrap => 1, width => '5%',  align => 'left',},
978
   partnumber         => { text =>  $locale->text('Part Number'),      nowrap => 1, width => '20%', align => 'left',},
979
   type_and_classific => { text =>  $locale->text('Typ'),              nowrap => 1, width => '5%' , align => 'left',},
980
   description        => { text =>  $locale->text('Part Description'), nowrap => 1, width => '50%', align => 'left',},
981
   lastcost           => { text =>  $locale->text('Purchase Prices'),  nowrap => 1, width => '45%', align => 'right',},
982
   total              => { text =>  $locale->text('Sale Prices'),      nowrap => 1,                 align => 'right',},
983
   bom                => { text =>  $locale->text('BOM'),                                           align => 'center',},
984
   partsgroup         => { text =>  $locale->text('Group'),                                         align => 'left',},
977 985
  );
978 986

  
979 987
  my @ROWS;
......
991 999
    $linetotal           = $form->format_amount(\%myconfig, $linetotal, 2);
992 1000
    $line_purchase_price = $form->format_amount(\%myconfig, $line_purchase_price, 2);
993 1001
    $href                = build_std_url("action=edit", qq|id=$form->{"id_$i"}|, "rowcount=$numrows", "currow=$i", "previousform=$previousform");
994
    map { $row{$_}{data} = "" } qw(qty unit partnumber description bom partsgroup runningnumber);
1002
    map { $row{$_}{data} = "" } qw(qty unit partnumber typ_and_class description bom partsgroup runningnumber);
995 1003

  
996 1004
    # last row
997 1005
    if (($i >= 1) && ($i == $numrows)) {
......
1011 1019
        $row{qty}{align}          = 'right';
1012 1020
      } else {
1013 1021
        $row{partnumber}{data}    = qq|$form->{"partnumber_$i"}|;
1014
        $row{partnumber}{link}     = $href;
1022
        $row{partnumber}{link}    = $href;
1015 1023
        $row{qty}{data}           = qq|<input name="qty_$i" size=5 value="$form->{"qty_$i"}">|;
1016 1024
        $row{runningnumber}{data} = qq|<input name="runningnumber_$i" size=3 value="$i">|;
1017 1025
        $row{bom}{data}   = sprintf qq|<input name="bom_$i" type=checkbox class=checkbox value=1 %s>|,
1018 1026
                                       $form->{"bom_$i"} ? 'checked' : '';
1019 1027
      }
1028
      # type impl $row{type_and_classific}{data} = $::request->presenter->type_abbreviation($form->{"type_$i"}).
1029
      $row{type_and_classific}{data} = $::request->presenter->type_abbreviation($form->{"assembly_$i"},$form->{"inventory_accno_id_$i"}).
1030
                                       $::request->presenter->classification_abbreviation($form->{"classification_id_$i"});
1020 1031
      push @row_hiddens,        qw(unit description partnumber partsgroup);
1021 1032
      $row{unit}{data}        = $form->{"unit_$i"};
1022 1033
      #Bei der Artikelbeschreibung und Warengruppe können Sonderzeichen verwendet
bin/mozilla/io.pl
159 159

  
160 160
  # column_index
161 161
  my @header_sort = qw(
162
    runningnumber partnumber description ship ship_missing qty price_factor
162
    runningnumber partnumber type_and_classific description ship ship_missing qty price_factor
163 163
    unit weight price_source sellprice discount linetotal
164 164
    bin stock_in_out
165 165
  );
......
169 169
  my %column_def = (
170 170
    runningnumber => { width => 5,     value => $locale->text('No.'),                  display => 1, },
171 171
    partnumber    => { width => 8,     value => $locale->text('Number'),               display => 1, },
172
    type_and_classific
173
                  => { width => 2,     value => $locale->text('Type'),                 display => 1, },
172 174
    description   => { width => 30,    value => $locale->text('Part Description'),     display => 1, },
173 175
    ship          => { width => 5,     value => $locale->text('Delivered'),            display => $is_s_p_order, },
174 176
    ship_missing  => { width => 5,     value => $locale->text('Not delivered'),        display => $show_ship_missing, },
......
295 297
    my $rows            = $form->numtextrows($form->{"description_$i"}, 30, 6);
296 298

  
297 299
    # quick delete single row
298
    $column_data{runningnumber} .= q|<a onclick= "$('#partnumber_| . $i . q|').val(''); $('#update_button').click();">| .
300
    $column_data{runningnumber}  = q|<a onclick= "$('#partnumber_| . $i . q|').val(''); $('#update_button').click();">| .
299 301
                                   q|<img height="10px" width="10px" src="image/cross.png" alt="| . $locale->text('Remove') . q|"></a> |;
300 302
    $column_data{runningnumber} .= $cgi->textfield(-name => "runningnumber_$i", -id => "runningnumber_$i", -size => 5,  -value => $i);    # HuT
301 303

  
302 304

  
303 305
    $column_data{partnumber}    = $cgi->textfield(-name => "partnumber_$i",    -id => "partnumber_$i",    -size => 12, -value => $form->{"partnumber_$i"});
306
   # type impl $column_data{type_and_classific} = $::request->presenter->type_abbreviation(($form->{"type_$i"}).
307
    $column_data{type_and_classific} = $::request->presenter->type_abbreviation($form->{"assembly_$i"},$form->{"inventory_accno_id_$i"}).
308
                                       $::request->presenter->classification_abbreviation($form->{"classification_id_$i"}) if $form->{"id_$i"};
304 309
    $column_data{description} = (($rows > 1) # if description is too large, use a textbox instead
305 310
                                ? $cgi->textarea( -name => "description_$i", -id => "description_$i", -default => $form->{"description_$i"}, -rows => $rows, -columns => 30)
306 311
                                : $cgi->textfield(-name => "description_$i", -id => "description_$i",   -value => $form->{"description_$i"}, -size => 30))
......
665 670
    map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{"taxaccounts_$i"} if !$form->{taxincluded};
666 671

  
667 672
    $form->{creditremaining} -= $amount;
668

  
669 673
    $form->{"runningnumber_$i"} = $i;
670 674

  
671 675
    # format amounts
bin/mozilla/wh.pl
677 677
  $form->{report_generator_output_format} = 'HTML' if !$form->{report_generator_output_format};
678 678

  
679 679
  my %filter;
680
  my @columns = qw(trans_id date warehouse_from bin_from warehouse_to bin_to partnumber partdescription chargenumber bestbefore trans_type comment qty employee oe_id projectnumber);
680
  my @columns = qw(trans_id date warehouse_from bin_from warehouse_to bin_to partnumber type_and_classific partdescription chargenumber bestbefore trans_type comment qty unit partunit employee oe_id projectnumber);
681 681

  
682 682
  # filter stuff
683
  map { $filter{$_} = $form->{$_} if ($form->{$_}) } qw(warehouse_id bin_id partnumber description chargenumber bestbefore);
683
  map { $filter{$_} = $form->{$_} if ($form->{$_}) } qw(warehouse_id bin_id classification_id partnumber description chargenumber bestbefore);
684 684

  
685 685
  $filter{qty_op} = WH->convert_qty_op($form->{qty_op});
686 686
  if ($filter{qty_op}) {
......
696 696

  
697 697
  my @hidden_variables = map { "l_${_}" } @columns;
698 698
  push @hidden_variables, qw(warehouse_id bin_id partnumber description chargenumber bestbefore qty_op qty qty_unit fromdate todate);
699
  push @hidden_variables, qw(classification_id);
699 700

  
700 701
  my %column_defs = (
701 702
    'date'            => { 'text' => $locale->text('Date'), },
......
707 708
    'bin_from'        => { 'text' => $locale->text('Bin From'), },
708 709
    'bin_to'          => { 'text' => $locale->text('Bin To'), },
709 710
    'partnumber'      => { 'text' => $locale->text('Part Number'), },
711
    'type_and_classific'
712
                      => { 'text' => $locale->text('Type'), },
710 713
    'partdescription' => { 'text' => $locale->text('Part Description'), },
711 714
    'chargenumber'    => { 'text' => $locale->text('Charge Number'), },
712 715
    'bestbefore'      => { 'text' => $locale->text('Best Before'), },
......
725 728
  my %column_alignment = map { $_ => 'right' } qw(qty);
726 729

  
727 730
  map { $column_defs{$_}->{visible} = $form->{"l_${_}"} ? 1 : 0 } @columns;
731
  $column_defs{type_and_classific}->{visible} = 1;
732
  $column_defs{type_and_classific}->{link} ='';
728 733

  
729 734
  $report->set_columns(%column_defs);
730 735
  $report->set_column_order(@columns);
......
763 768
   my $idx       = 0;
764 769

  
765 770
  foreach my $entry (@contents) {
771
    # type impl $entry->{type_and_classific} = $::request->presenter->type_abbreviation($entry->{type}).
772
    $entry->{type_and_classific} = $::request->presenter->type_abbreviation($entry->{assembly},$entry->{inventory_accno_id}).
773
                                   $::request->presenter->classification_abbreviation($entry->{classification_id});
766 774
    $entry->{qty}        = $form->format_amount_units('amount'     => $entry->{qty},
767 775
                                                      'part_unit'  => $entry->{partunit},
768 776
                                                      'conv_units' => 'convertible');
......
852 860
  my $sort_col     = $form->{sort};
853 861

  
854 862
  my %filter;
855
  my @columns = qw(warehousedescription bindescription partnumber partdescription chargenumber bestbefore qty stock_value);
863
  my @columns = qw(warehousedescription bindescription partnumber type_and_classific partdescription chargenumber bestbefore comment qty partunit stock_value);
856 864

  
857 865
  # filter stuff
858
  map { $filter{$_} = $form->{$_} if ($form->{$_}) } qw(warehouse_id bin_id partstypes_id partnumber description chargenumber bestbefore date include_invalid_warehouses);
866
  map { $filter{$_} = $form->{$_} if ($form->{$_}) } qw(warehouse_id bin_id classification_id partnumber description chargenumber bestbefore date include_invalid_warehouses);
859 867

  
860 868
  # show filter stuff also in report
861 869
  my @options;
870
  my $currentdate = $form->current_date(\%myconfig);
871
  push @options, $locale->text('Printdate') . " : ".$locale->date(\%myconfig, $currentdate, 1);
872

  
862 873
  # dispatch all options
863 874
  my $dispatch_options = {
864 875
   warehouse_id   => sub { push @options, $locale->text('Warehouse') . " : " .
......
866 877
   bin_id         => sub { push @options, $locale->text('Bin') . " : " .
867 878
                                            SL::DB::Manager::Bin->find_by(id => $form->{bin_id})->description},
868 879
   partnumber     => sub { push @options, $locale->text('Partnumber')     . " : $form->{partnumber}"},
880
   classification_id => sub { push @options, $locale->text('Parts Classification'). " : ".
881
     SL::DB::Manager::PartsClassification->get_first(where => [ id => $form->{classification_id} ] )->description; },
869 882
   description    => sub { push @options, $locale->text('Description')    . " : $form->{description}"},
870 883
   chargenumber   => sub { push @options, $locale->text('Charge Number')  . " : $form->{chargenumber}"},
871 884
   bestbefore     => sub { push @options, $locale->text('Best Before')    . " : $form->{bestbefore}"},
872
   date           => sub { push @options, $locale->text('Date')           . " : $form->{date}"},
873 885
   include_invalid_warehouses    => sub { push @options, $locale->text('Include invalid warehouses ')},
874 886
  };
875 887
  foreach (keys %filter) {
876 888
   $dispatch_options->{$_}->() if $dispatch_options->{$_};
877 889
  }
890
  push @options, $locale->text('Stock Qty for Date') . " " . $locale->date(\%myconfig, $form->{date}?$form->{date}:$currentdate, 1);
891

  
878 892
  # / end show filter stuff also in report
879 893

  
880 894
  $filter{qty_op} = WH->convert_qty_op($form->{qty_op});
......
895 909
  my @hidden_variables = map { "l_${_}" } @columns;
896 910
  push @hidden_variables, qw(warehouse_id bin_id partnumber partstypes_id description chargenumber bestbefore qty_op qty qty_unit partunit l_warehousedescription l_bindescription);
897 911
  push @hidden_variables, qw(include_empty_bins subtotal include_invalid_warehouses date);
912
  push @hidden_variables, qw(classification_id);
898 913

  
899 914
  my %column_defs = (
900 915
    'warehousedescription' => { 'text' => $locale->text('Warehouse'), },
901 916
    'bindescription'       => { 'text' => $locale->text('Bin'), },
902 917
    'partnumber'           => { 'text' => $locale->text('Part Number'), },
918
    'type_and_classific'   => { 'text' => $locale->text('Type'), },
903 919
    'partdescription'      => { 'text' => $locale->text('Part Description'), },
904 920
    'chargenumber'         => { 'text' => $locale->text('Charge Number'), },
905 921
    'bestbefore'           => { 'text' => $locale->text('Best Before'), },
......
916 932

  
917 933
  map { $column_defs{$_}->{visible} = $form->{"l_${_}"} ? 1 : 0 } @columns;
918 934

  
935
  $column_defs{type_and_classific}->{visible} = 1;
936
  $column_defs{type_and_classific}->{link} ='';
937

  
919 938
  $report->set_columns(%column_defs);
920 939
  $report->set_column_order(@columns);
921 940

  
......
950 969
  my $last_nr  = $first_nr + $pages->{per_page};
951 970

  
952 971
  foreach my $entry (@contents) {
972

  
973
    # type impl $entry->{type_and_classific} = $::request->presenter->type_abbreviation($entry->{type}).
974
    $entry->{type_and_classific} = $::request->presenter->type_abbreviation($entry->{assembly},$entry->{inventory_accno_id}).
975
                                   $::request->presenter->classification_abbreviation($entry->{classification_id});
953 976
    map { $subtotals{$_} += $entry->{$_} } @subtotals_columns;
954 977
    $total_stock_value   += $entry->{stock_value} * 1;
955 978
    $entry->{qty}         = $form->format_amount(\%myconfig, $entry->{qty});
doc/changelog
4 4

  
5 5
2016-xx-xx - Release 3.4.x Unstable
6 6

  
7
große Features:
8

  
9
- Artikel-Klassifizierung
10
    
11
    Die Klassifizierung von Artikeln
12
    Sie dient einer weiteren Gliederung um zum Beispiel den Einkauf vom Verkauf zu trennen, etc.
13
    
14
    Gekennzeichnet durch eine Beschreibung (z.B. "Einkauf") und ein Kürzel (z.B. "E")
15
    Flexibel änderbar und erweiterbar.
16
    
17
    - Neue Datenbanktablle und Rose-Objekte, sowie Controller zum Bearbeiten der Tabelle
18
    
19
    - Zwei-Zeichen Abkürzung:
20
    
21
    Der Typ des Artikel und die Klassifizierung werden durch zwei Buchstaben dargestellt.
22
    Der erste Buchstabe  ist eine Lokalisierung des Typs des Artikel ('P','A','S') ,
23
    deutch 'W', 'E', und 'D' für Ware Erzeugnis oder Dienstleistung, ggf. weitere Typen.
24
    Der zweite Buchstabe ist eine Lokalisierung der Klassifizierungsabkürzung (abbreviation).
25
    
26
    Die Abkürzungen sind aus dem Part Presenter abholbar:
27
    -  SL::Presenter::Part->type_abbreviation($assembly,inventory_accno_id) bzw
28
        bei neuer Type Implementierung SL::Presenter::Part->type_abbreviation($type_id)
29
    -  SL::Presenter::Part->classification_abbreviation($classification_id)
30
    
31
    Wenn im ERP-Dokument nach einer Artikelnummer oder Beschreibung gesucht wird,
32
    diese in den Stammdaten vorhanden ist,
33
    aber der Artikeltyp leer oder falsch ist, bzw im Typ for_purchase bzw for_sale nicht gesetzt ist,
34
    wird die Fehlermeldung "Gesuchter Artikel ist nicht für den Einkauf bzw Verkauf" gemeldet
35
    
36
    Anpassung des CSV Import,
37
    nun wird alternativ zur 'type'-Spalte die 'pclass'-Spalte mit zwei Buchstaben geparsed und entsprechend
38
    classification_id,assembly sowie inventory_accno_id gesetzt (oder type_id falls neue Implementierung eingebaut).
39

  
7 40
kleinere neue Features und Detailverbesserungen:
8 41

  
9 42
  - SEPA Überweisungen zusätzlich Kunden- oder Lieferantennummer im Verwendungszweck vorbelegen
locale/de/all
297 297
  'Article'                     => 'Artikel',
298 298
  'Article Code'                => 'Artikelkürzel',
299 299
  'Article Code missing!'       => 'Artikelkürzel fehlt',
300
  'Article classification'      => 'Artikel-Klassifizierung',
300 301
  'Article type'                => 'Artikeltyp',
301 302
  'Articles'                    => 'Artikel',
302 303
  'As a result, the saved onhand values of the present goods can be stored into a warehouse designated by you, or will be reset for a proper warehouse tracking' => 'Als Konsequenz k&ouml;nnen die gespeicherten Mengen entweder in ein Lager &uuml;berf&uuml;hrt werden, oder f&uuml;r eine frische Lagerverwaltung resettet werden.',
303 304
  'Assemblies'                  => 'Erzeugnisse',
304
  'Assemblies can not be imported (yet). But the type column is used for sanity checks on price updates in order to prevent that articles with the wrong type will be updated.' => 'Erzeugnisse können (noch) nicht importiert werden. Aber die Typ-Spalte wird für Plausibilitätsprüfungen bei Preisaktualisierungen verwendet, um zu verhindern, dass Artikel vom falschen Typ aktualisiert werden.',
305 305
  'Assembly'                    => 'Erzeugnis',
306
  'Assembly (typeabbreviation)' => 'E',
306 307
  'Assembly Description'        => 'Erzeugnis-Beschreibung',
307 308
  'Assembly Number'             => 'Erzeugnis-Nummer',
308 309
  'Assembly Number missing!'    => 'Erzeugnisnummer fehlt!',
......
662 663
  'Create a new delivery term'  => 'Neue Lieferbedingungen anlegen',
663 664
  'Create a new department'     => 'Eine neue Abteilung erfassen',
664 665
  'Create a new group'          => 'Neue Benutzergruppe erfassen',
666
  'Create a new parts classification' => 'Erzeuge eine neue Artikel-Klassifizierung',
665 667
  'Create a new payment term'   => 'Neue Zahlungsbedingungen anlegen',
666 668
  'Create a new predefined text' => 'Einen neuen vordefinierten Textblock anlegen',
667 669
  'Create a new price rule'     => 'Neue Preisregel anlegen',
......
1108 1110
  'Edit general settings'       => 'Grundeinstellungen bearbeiten',
1109 1111
  'Edit greetings'              => 'Anreden bearbeiten',
1110 1112
  'Edit note'                   => 'Notiz bearbeiten',
1113
  'Edit parts classification'   => 'Bearbeite eine Artikel-Klassifizierung',
1111 1114
  'Edit payment term'           => 'Zahlungsbedingungen bearbeiten',
1112 1115
  'Edit picture'                => 'Bild bearbeiten',
1113 1116
  'Edit predefined text'        => 'Vordefinierten Textblock bearbeiten',
......
1444 1447
  'If all of the following match' => 'Wenn alle der folgenden Bedingungen zutreffen',
1445 1448
  'If amounts differ more than "Maximal amount difference" (see settings), this item is marked as invalid.' => 'Weichen die Beträge mehr als die "maximale Betragsabweichung" (siehe Einstellungen) ab, so wird diese Position als ungültig markiert.',
1446 1449
  'If checked the taxkey will not be exported in the DATEV Export, but only IF chart taxkeys differ from general ledger taxkeys' => 'Falls angehakt wird der DATEV-Steuerschlüssel bei Buchungen auf dieses Konto nicht beim DATEV-Export mitexportiert, allerdings nur wenn zusätzlich der Konto-Steuerschlüssel vom Buchungs (Hauptbuch) Steuerschlüssel abweicht',
1450
  'If column \'pclass\' is present the article type is then irrelevant or used as default ' => 'Falls Spalte \'pclass\' existiert, wird dies nur als default genommen',
1447 1451
  'If configured this bin will be preselected for all new parts. Also this bin will be used as the master default bin, if default transfer out with master bin is activated.' => 'Falls konfiguriert, wird dieses Lager mit Lagerplatz für neu angelegte Waren vorausgewählt.',
1448 1452
  'If disabled purchase delivery orders can only be created by conversion from existing requests for quotations and purchase orders.' => 'Falls deaktiviert, so können Einkaufslieferscheine nur durch Umwandlung aus bestehenden Preisanfragen und Lieferantenaufträgen angelegt werden.',
1449 1453
  'If disabled purchase invoices can only be created by conversion from existing requests for quotations, purchase orders and purchase delivery orders.' => 'Falls deaktiviert, so können Einkaufsrechnungen nur durch Umwandlung aus bestehenden Preisanfragen, Lieferantenaufträgen und Einkaufslieferscheinen angelegt werden.',
......
1455 1459
  'If enabled purchase and sales records cannot be saved if no transaction description has been entered.' => 'Wenn angeschaltet, so können Einkaufs- und Verkaufsbelege nicht gespeichert werden, solange keine Vorgangsbezeichnung eingegeben wurde.',
1456 1460
  'If left empty the default sender from the kivitendo configuration will be used (key \'email_from\' in section \'periodic_invoices\'; current value: #1).' => 'Falls leer, so wird der Standardabsender aus der kivitendo-Konfiguration genutzt (Schlüssel »email_from« in Abschnitt »periodic_invoices«; aktueller Wert: #1).',
1457 1461
  'If missing then the start date will be used.' => 'Falls es fehlt, so wird die erste Rechnung für das Startdatum erzeugt.',
1458
  'If the article type is set to \'mixed\' then a column called \'type\' must be present.' => 'Falls der Artikeltyp auf \'gemischt\' gestellt wird, muss eine Spalte namens \'type\' vorhanden sein.',
1462
  'If the article type is set to \'mixed\' then a column called \'type\' or called \'pclass\' must be present.' => 'Falls der Artikeltyp auf \'mixed\' eingestellt muß entwder die Spale \'type\' oder die Spalte \'pclass\' vorhanden sein',
1459 1463
  'If the automatic creation of invoices for fees and interest is switched on for a dunning level then the following accounts will be used for the invoice.' => 'Wenn das automatische Erstellen einer Rechnung &uuml;ber Mahngeb&uuml;hren und Zinsen f&uuml;r ein Mahnlevel aktiviert ist, so werden die folgenden Konten f&uuml;r die Rechnung benutzt.',
1460 1464
  'If the database user listed above does not have the right to create a database then enter the name and password of the superuser below:' => 'Falls der oben genannte Datenbankbenutzer nicht die Berechtigung zum Anlegen neuer Datenbanken hat, so k&ouml;nnen Sie hier den Namen und das Passwort des Datenbankadministratoraccounts angeben:',
1461 1465
  'If the default transfer out always succeed use this bin for negative stock quantity.' => 'Standardlagerplatz für Auslagern ohne Prüfung auf Bestand',
......
1572 1576
  'It will simply set the taxkey to 0 (meaning "no taxes") which is the correct value for such inventory transactions.' => 'Es wird einfach die Steuerschlüssel auf  0 setzen, was "keine Steuer" bedeutet und für solche Warenbestandsbuchungen der richtige Wert ist.',
1573 1577
  'Italy'                       => 'Italien',
1574 1578
  'Item deleted!'               => 'Artikel gelöscht!',
1579
  'Item does not exists in File' => 'Gesuchter Artikel nicht in den Stammdaten vorhanden.',
1575 1580
  'Item mode'                   => 'Artikelmodus',
1576 1581
  'Item multi selection with qty' => 'Artikel-Mehrfachauswahl mit Menge',
1577
  'Item not on file!'           => 'Dieser Artikel ist nicht in der Datenbank!',
1578 1582
  'Item values'                 => 'Artikelwerte',
1579 1583
  'Item variables'              => 'Artikelvariablen',
1580 1584
  'Jahresverkehrszahlen neu'    => 'Jahresverkehrszahlen neu',
......
1735 1739
  'Media \'#1\' is not supported yet/anymore.' => 'Das Medium \'#1\' wird noch nicht oder nicht mehr unterstützt.',
1736 1740
  'Medium Number'               => 'Datentr&auml;gernummer',
1737 1741
  'Memo'                        => 'Memo',
1742
  'Merchandise'                 => 'Handelsware',
1743
  'Merchandise (typeabbreviation)' => 'H',
1738 1744
  'Message'                     => 'Nachricht',
1739 1745
  'Method'                      => 'Verfahren',
1740 1746
  'Microfiche'                  => 'Mikrofilm',
......
1751 1757
  'Missing taxkeys in invoices with taxes.' => 'Fehlende Steuerschl&uuml;ssel in Rechnungen mit Steuern',
1752 1758
  'Missing transport cost: #1  Are you sure?' => 'Fehlender Transportkosten-Artikel #1 Trotzdem speichern?',
1753 1759
  'Mitarbeiter'                 => 'Mitarbeiter',
1754
  'Mixed (requires column "type")' => 'Gemischt (erfordert Spalte "type")',
1760
  'Mixed (requires column "type" or "pclass")' => 'Gemischt (Spalte "type" oder "pclass" notwendig',
1755 1761
  'Mobile'                      => 'Mobiltelefon',
1756 1762
  'Mobile1'                     => 'Mobil 1',
1757 1763
  'Mobile2'                     => 'Mobil 2',
......
1789 1795
  'New Password'                => 'Neues Passwort',
1790 1796
  'New Purchase Price Rule'     => 'Neue Einkaufspreisregel',
1791 1797
  'New Sales Price Rule'        => 'Neue Verkaufspreisregel',
1792
  'New assembly'                => 'Neues Erzeugnis',
1793 1798
  'New client #1: The database configuration fields "host", "port", "name" and "user" must not be empty.' => 'Neuer Mandant #1: Die Datenbankkonfigurationsfelder "Host", "Port" und "Name" dürfen nicht leer sein.',
1794 1799
  'New client #1: The name must be unique and not empty.' => 'Neuer Mandant #1: Der Name darf nicht leer und muss eindeutig sein.',
1795 1800
  'New contact'                 => 'Neue Ansprechperson',
......
1801 1806
  'New row, description'        => 'Neue Zeile, Artikelbeschreibung',
1802 1807
  'New row, partnumber'         => 'Neue Zeile, Nummer',
1803 1808
  'New sales order'             => 'Neuer Auftrag',
1804
  'New service'                 => 'Neue Dienstleistung',
1805 1809
  'New shipto'                  => 'Neue Lieferadresse',
1806 1810
  'New vendor'                  => 'Neuer Lieferant',
1807 1811
  'New window/tab'              => 'Neues Fenster/Tab',
......
1847 1851
  'No or an unknown authenticantion module specified in "config/kivitendo.conf".' => 'Es wurde kein oder ein unbekanntes Authentifizierungsmodul in "config/kivitendo.conf" angegeben.',
1848 1852
  'No part was found matching the search parameters.' => 'Es wurde kein Artikel gefunden, auf den die Suchparameter zutreffen.',
1849 1853
  'No part was selected.'       => 'Es wurde kein Artikel ausgewählt',
1854
  'No parts classification has been created yet.' => 'Keine Artikel-Klassifizierung erzeugt.',
1850 1855
  'No payment term has been created yet.' => 'Es wurden noch keine Zahlungsbedingungen angelegt.',
1851 1856
  'No picture has been uploaded' => 'Es wurde kein Bild hochgeladen',
1852 1857
  'No picture uploaded yet'     => 'Noch kein Bild hochgeladen',
......
1889 1894
  'None'                        => 'Kein',
1890 1895
  'None (PriceSource Discount)' => 'Freier Rabatt',
1891 1896
  'None (PriceSource)'          => 'Freier Preis',
1897
  'None (typeabbreviation)'     => '-',
1892 1898
  'Normal'                      => 'Normal',
1893 1899
  'Normal users cannot log in.' => 'Normale Benutzer können sich nicht anmelden.',
1894 1900
  'Normalize Customer / Vendor names' => 'Normalisierung Kunden- / Lieferantennamen',
......
2011 2017
  'POSTED'                      => 'Gebucht',
2012 2018
  'POSTED AS NEW'               => 'Als neu gebucht',
2013 2019
  'PRINTED'                     => 'Gedruckt',
2020
  'PType'                       => 'Typ',
2014 2021
  'Package name'                => 'Paketname',
2015 2022
  'Packing Lists'               => 'Lieferschein',
2016 2023
  'Page'                        => 'Seite',
......
2020 2027
  'Part'                        => 'Ware',
2021 2028
  'Part "#1" has chargenumber or best before date set. So it cannot be transfered automatically.' => 'Bei Artikel "#1" ist eine Chargenummer oder ein Mindesthaltbarkeitsdatum vergeben. Deshalb kann dieser Artikel nicht automatisch ausgelagert werden.',
2022 2029
  'Part (database ID)'          => 'Artikel (Datenbank-ID)',
2030
  'Part (typeabbreviation)'     => 'W',
2031
  'Part Classification'         => 'Artikel-Klassifizierung',
2023 2032
  'Part Description'            => 'Artikelbeschreibung',
2024 2033
  'Part Description missing!'   => 'Artikelbezeichnung fehlt!',
2025 2034
  'Part Notes'                  => 'Bemerkungen',
2026 2035
  'Part Number'                 => 'Artikelnummer',
2027 2036
  'Part Number missing!'        => 'Artikelnummer fehlt!',
2028
  'Part Unit'                   => 'Artikeleinheit',
2037
  'Part Unit'                   => 'Einheit des Artikels',
2029 2038
  'Part picker'                 => 'Artikelauswahl',
2030 2039
  'Part_br_Description'         => 'Beschreibung',
2031 2040
  'Partial invoices'            => 'Teilrechnungen',
......
2033 2042
  'Partnumber must not be set to empty!' => 'Die Artikelnummer darf nicht auf leer ge&auml;ndert werden.',
2034 2043
  'Partnumber not unique!'      => 'Artikelnummer bereits vorhanden!',
2035 2044
  'Parts'                       => 'Waren',
2045
  'Parts Classification'        => 'Artikel-Klassifizierung',
2046
  'Parts Classifications'       => 'Artikel-Klassifizierung',
2036 2047
  'Parts Inventory'             => 'Warenliste',
2037 2048
  'Parts Master Data'           => 'Artikelstammdaten',
2038 2049
  'Parts must have an entry type.' => 'Waren m&uuml;ssen eine Buchungsgruppe haben.',
......
2183 2194
  'Print template base file name' => 'Druckvorlagen-Basisdateiname',
2184 2195
  'Print templates'             => 'Druckvorlagen',
2185 2196
  'Print templates to use'      => 'Zu verwendende Druckvorlagen',
2197
  'Printdate'                   => '',
2186 2198
  'Printer'                     => 'Drucker',
2187 2199
  'Printer Command'             => 'Druckbefehl',
2188 2200
  'Printer Description'         => 'Druckerbeschreibung',
......
2196 2208
  'Private Phone'               => 'Privates Tel.',
2197 2209
  'Problem'                     => 'Problem',
2198 2210
  'Produce Assembly'            => 'Erzeugnis fertigen',
2211
  'Production'                  => 'Produktion',
2212
  'Production (typeabbreviation)' => 'P',
2199 2213
  'Productivity'                => 'Produktivität',
2200 2214
  'Profit determination'        => 'Gewinnermittlung',
2201 2215
  'Proforma Invoice'            => 'Proformarechnung',
......
2219 2233
  'Proposal'                    => 'Vorschlag',
2220 2234
  'Proposals'                   => 'Vorschläge',
2221 2235
  'Prozentual/Absolut'          => 'Prozentual/Absolut',
2236
  'Purchase'                    => 'Einkauf',
2237
  'Purchase (typeabbreviation)' => 'E',
2222 2238
  'Purchase Delivery Order'     => 'Einkaufslieferschein',
2223 2239
  'Purchase Delivery Orders'    => 'Einkaufslieferscheine',
2224 2240
  'Purchase Delivery Orders deleteable' => 'Einkaufslieferscheine löschbar',
......
2421 2437
  'Saldo neu'                   => 'Saldo neu',
2422 2438
  'Saldo per'                   => 'Saldo per',
2423 2439
  'Sale Prices'                 => 'Verkaufspreise',
2440
  'Sales'                       => 'Verkauf',
2441
  'Sales (typeabbreviation)'    => 'V',
2424 2442
  'Sales Delivery Order'        => 'Verkaufslieferschein',
2425 2443
  'Sales Delivery Orders'       => 'Verkaufslieferscheine',
2426 2444
  'Sales Delivery Orders deleteable' => 'Verkaufslieferscheine löschbar',
......
2543 2561
  'Serial No.'                  => 'Seriennummer',
2544 2562
  'Serial Number'               => 'Seriennummer',
2545 2563
  'Service'                     => 'Dienstleistung',
2564
  'Service (typeabbreviation)'  => 'D',
2546 2565
  'Service Items'               => 'Dienstleistungen',
2547 2566
  'Service Number missing!'     => 'Dienstleistungsnummer fehlt!',
2548 2567
  'Service, assembly or part'   => 'Dienstleistung, Erzeugnis oder Ware',
......
2796 2815
  'That export does not exist.' => 'Dieser Export existiert nicht.',
2797 2816
  'That is why kivitendo could not find a default currency.' => 'Daher konnte kivitendo keine Standardwährung finden.',
2798 2817
  'The \'name\' is the field shown to the user during login.' => 'Der \'Name\' ist derjenige, der dem Benutzer beim Login angezeigt wird.',
2818
  'The \'pclass\' column has the same abbreviation like a part export. The first letter is for the type Part,Assembly or Service, the second(and third) for Part Classification' => 'Die Spalte \'pclass\' besteht aus zwei Buchstaben entsprechend dem Export. Der erste Buchstabe ist für \'W\'=Ware \'E\'=Erzeugnis oder \'D\' für Dienstleistung, der zweite steht für den Artikeltyp, z.B. E,V,H,P oder - ',
2799 2819
  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
2800 2820
  'The AP transaction #1 has been deleted.' => 'Die Kreditorenbuchung #1 wurde gelöscht.',
2801 2821
  'The AR transaction #1 has been deleted.' => 'Die Debitorenbuchung #1 wurde gelöscht.',
......
2812 2832
  'The SEPA export has been created.' => 'Der SEPA-Export wurde erstellt',
2813 2833
  'The SEPA strings have been saved.' => 'Die bei SEPA-Überweisungen verwendeten Begriffe wurden gespeichert.',
2814 2834
  'The WebDAV feature has been used.' => 'Das WebDAV-Feature wurde benutzt.',
2835
  'The abbreviation is missing.' => 'Abkürzung fehlt',
2815 2836
  'The acceptance status has been created.' => 'Der Abnahmestatus wurde angelegt.',
2816 2837
  'The acceptance status has been deleted.' => 'Der Abnahmestatus wurde gelöscht.',
2817 2838
  'The acceptance status has been saved.' => 'Der Abnahmestatus wurde gespeichert.',
......
2846 2867
  'The base unit does not exist.' => 'Die Basiseinheit existiert nicht.',
2847 2868
  'The base unit relations must not contain loops (e.g. by saying that unit A\'s base unit is B, B\'s base unit is C and C\'s base unit is A) in row %d.' => 'Die Beziehungen der Einheiten d&uuml;rfen keine Schleifen beinhalten (z.B. wenn gesagt wird, dass Einheit As Basiseinheit B, Bs Basiseinheit C und Cs Basiseinheit A ist) in Zeile %d.',
2848 2869
  'The basic client tables have not been created for this client\'s database yet.' => 'Die grundlegenden Mandantentabellen wurden in der für diesen Mandanten konfigurierten Datenbank noch nicht angelegt.',
2870
  'The basic parts classification cannot be deleted.' => '',
2849 2871
  'The body is missing.'        => 'Der Text fehlt',
2850 2872
  'The booking group has been created.' => 'Die Buchungsgruppe wurde erstellt.',
2851 2873
  'The booking group has been deleted.' => 'Die Buchungsgruppe wurde gelöscht.',
......
2915 2937
  'The discounted amount will be shown in documents.' => 'Der Rabattbetrag wird in Belegen ausgewiesen.',
2916 2938
  'The document has been changed by another user. No mail was sent. Please reopen it in another window and copy the changes to the new window' => 'Die Daten wurden bereits von einem anderen Benutzer verändert. Deshalb ist das Dokument ungültig und es wurde keine E-Mail verschickt. Bitte öffnen Sie das Dokument erneut in einem extra Fenster und übertragen Sie die Daten',
2917 2939
  'The document has been changed by another user. Please reopen it in another window and copy the changes to the new window' => 'Die Daten wurden bereits von einem anderen Benutzer verändert. Deshalb ist das Dokument ungültig. Bitte öffnen Sie das Dokument erneut in einem extra Fenster und übertragen Sie die Daten',
2918
  'The documents have been sent to the printer \'#1\'.' => 'Die Dokumente wurden an den Drucker \'#1\' geschickt.',
2940
  'The documents have been sent to the printer \'#1\'.' => 'Die Dokumente sind zum Drucker \'#1\' geschickt',
2919 2941
  'The dunning process started' => 'Der Mahnprozess ist gestartet.',
2920 2942
  'The dunnings have been printed.' => 'Die Mahnung(en) wurden gedruckt.',
2921 2943
  'The email has been sent.'    => 'Die E-Mail wurde verschickt.',
......
2976 2998
  'The order has been deleted'  => 'Der Auftrag wurde gelöscht.',
2977 2999
  'The order has been saved'    => 'Der Auftrag wurde gespeichert.',
2978 3000
  'The package name is invalid.' => 'Der Paketname ist ungültig.',
3001
  'The parts classification has been created.' => 'Die Artikel-Klassifizierung ist erzeugt',
3002
  'The parts classification has been deleted.' => 'Die Artikel-Klassifizierung ist gelöscht',
3003
  'The parts classification has been saved.' => 'Die Artikel-Klassifizierung ist gespeichert',
3004
  'The parts classification is in use and cannot be deleted.' => 'Die Artikel-Klassifizierung ist in Verwendung, kann deshalb nicht gelöscht werden.',
2979 3005
  'The parts for this delivery order have already been transferred in.' => 'Die Artikel dieses Lieferscheins wurden bereits eingelagert.',
2980 3006
  'The parts for this delivery order have already been transferred out.' => 'Die Artikel dieses Lieferscheins wurden bereits ausgelagert.',
2981 3007
  'The parts have been removed.' => 'Die Waren wurden aus dem Lager entnommen.',
... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.

Auch abrufbar als: Unified diff