commit cd07d28992bd8778f0702a9ea0dc937c6d93fd54
Author: Moritz Bunkus <m.bunkus@linet.de>
Date:   Wed Feb 1 14:20:21 2017 +0100

    SimpleSystemSetting: Umstellung von »Artikel-Klassifizierungen«

diff --git a/SL/Controller/PartClassification.pm b/SL/Controller/PartClassification.pm
deleted file mode 100644
index da1cb626d..000000000
--- a/SL/Controller/PartClassification.pm
+++ /dev/null
@@ -1,230 +0,0 @@
-package SL::Controller::PartClassification;
-
-use strict;
-
-use parent qw(SL::Controller::Base);
-
-use SL::DB::PartClassification;
-use SL::Helper::Flash;
-
-use Rose::Object::MakeMethods::Generic
-(
- scalar => [ qw(part_classification) ],
-);
-
-__PACKAGE__->run_before('check_auth');
-__PACKAGE__->run_before('load_part_classification', only => [ qw(edit update destroy) ]);
-
-#
-# This Controller is responsible for creating,editing or deleting
-# Part Classifications.
-#
-# The use of Part Classifications is described in SL::DB::PartClassification
-#
-#
-
-# List all available part classifications
-#
-
-sub action_list {
-  my ($self) = @_;
-
-  $self->render('part_classification/list',
-                title                => $::locale->text('Parts Classifications'),
-                PART_CLASSIFICATIONS => SL::DB::Manager::PartClassification->get_all_sorted);
-}
-
-# A Form for a new creatable part classifications is generated
-#
-sub action_new {
-  my ($self) = @_;
-
-  $self->{part_classification} = SL::DB::PartClassification->new;
-  $self->render('part_classification/form', title => $::locale->text('Create a new parts classification'));
-}
-
-# Edit an existing part classifications
-#
-sub action_edit {
-  my ($self) = @_;
-  $self->render('part_classification/form', title => $::locale->text('Edit parts classification'));
-}
-
-# A new part classification is saved
-#
-sub action_create {
-  my ($self) = @_;
-
-  $self->{part_classification} = SL::DB::PartClassification->new;
-  $self->create_or_update;
-}
-
-# An existing part classification is saved
-#
-sub action_update {
-  my ($self) = @_;
-  $self->create_or_update;
-}
-
-# An existing part classification is deleted
-#
-# The basic classifications cannot be deleted, also classifications which are in use
-#
-sub action_destroy {
-  my ($self) = @_;
-
-  if ( $self->{part_classification}->id < 5 ) {
-    flash_later('error', $::locale->text('The basic parts classification cannot be deleted.'));
-  }
-  elsif (eval { $self->{part_classification}->delete; 1; }) {
-    flash_later('info',  $::locale->text('The parts classification has been deleted.'));
-  } else {
-    flash_later('error', $::locale->text('The parts classification is in use and cannot be deleted.'));
-  }
-
-  $self->redirect_to(action => 'list');
-}
-# reordering the lines
-#
-sub action_reorder {
-  my ($self) = @_;
-
-  SL::DB::PartClassification->reorder_list(@{ $::form->{part_classification_id} || [] });
-
-  $self->render(\'', { type => 'json' });
-}
-
-#
-# filters
-#
-
-# check authentication, only "config" is allowed
-#
-sub check_auth {
-  $::auth->assert('config');
-}
-
-#
-# helpers
-#
-
-# submethod for update the database
-#
-sub create_or_update {
-  my $self   = shift;
-  my $is_new = !$self->{part_classification}->id;
-
-  $::form->{part_classification}->{used_for_purchase} = 0 if ! $::form->{part_classification}->{used_for_purchase};
-  $::form->{part_classification}->{used_for_sale}     = 0 if ! $::form->{part_classification}->{used_for_sale};
-  $::form->{part_classification}->{report_separate}   = 0 if ! $::form->{part_classification}->{report_separate};
-
-  my $params = delete($::form->{part_classification}) || { };
-
-  $self->{part_classification}->assign_attributes(%{ $params });
-
-  my @errors = $self->{part_classification}->validate;
-
-  if (@errors) {
-    flash('error', @errors);
-    $self->render('part_classification/form', title => $is_new ? $::locale->text('Create a new parts classification') : $::locale->text('Edit parts classification'));
-    return;
-  }
-
-  $self->{part_classification}->save;
-
-  flash_later('info', $is_new ? $::locale->text('The parts classification has been created.') : $::locale->text('The parts classification has been saved.'));
-  $self->redirect_to(action => 'list');
-}
-
-# submethod for loading one item from the database
-#
-sub load_part_classification {
-  my ($self) = @_;
-  $self->{part_classification} = SL::DB::PartClassification->new(id => $::form->{id})->load;
-}
-
-1;
-
-
-
-__END__
-
-=encoding utf-8
-
-=head1 NAME
-
-SL::Controller::PartClassification
-
-=head1 SYNOPSIS
-
-This Controller is responsible for creating,editing or deleting
-Part Classifications.
-
-=head1 DESCRIPTION
-
-The use of Part Classifications is described in L<SL::DB::PartClassification>
-
-=head1 METHODS
-
-=head2 action_create
-
- $self->action_create();
-
-A new part classification is saved
-
-
-
-=head2 action_destroy
-
- $self->action_destroy();
-
-An existing part classification is deleted
-
-The basic classifications cannot be deleted, also classifications which are in use
-
-
-
-=head2 action_edit
-
- $self->action_edit();
-
-Edit an existing part classifications
-
-
-
-=head2 action_list
-
- $self->action_list();
-
-List all available part classifications
-
-
-
-=head2 action_new
-
- $self->action_new();
-
-A Form for a new creatable part classifications is generated
-
-
-
-=head2 action_reorder
-
- $self->action_reorder();
-
-reordering the lines
-
-
-
-=head2 action_update
-
- $self->action_update();
-
-An existing part classification is saved
-
-
-=head1 AUTHOR
-
-Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>
-
-=cut
diff --git a/SL/Controller/SimpleSystemSetting.pm b/SL/Controller/SimpleSystemSetting.pm
index 9ce91f9f9..f03d97bef 100644
--- a/SL/Controller/SimpleSystemSetting.pm
+++ b/SL/Controller/SimpleSystemSetting.pm
@@ -40,6 +40,23 @@ my %supported_types = (
     ],
   },
 
+  part_classification => {
+    # Make locales.pl happy: $self->render("simple_system_setting/_part_classification_form")
+    class  => 'PartClassification',
+    titles => {
+      list => t8('Part classifications'),
+      add  => t8('Add part classification'),
+      edit => t8('Edit part classification'),
+    },
+    list_attributes => [
+      { title => t8('Description'),       formatter => sub { t8($_[0]->description) } },
+      { title => t8('Type abbreviation'), formatter => sub { t8($_[0]->abbreviation) } },
+      { title => t8('Used for Purchase'), formatter => sub { $_[0]->used_for_purchase ? t8('yes') : t8('no') } },
+      { title => t8('Used for Sale'),     formatter => sub { $_[0]->used_for_sale     ? t8('yes') : t8('no') } },
+      { title => t8('Report separately'), formatter => sub { $_[0]->report_separate   ? t8('yes') : t8('no') } },
+    ],
+  },
+
   parts_group => {
     # Make locales.pl happy: $self->render("simple_system_setting/_parts_group_form")
     class  => 'PartsGroup',
diff --git a/locale/de/all b/locale/de/all
index 7c4da9016..d14e80d13 100644
--- a/locale/de/all
+++ b/locale/de/all
@@ -206,6 +206,7 @@ $self->{texts} = {
   'Add new record template'     => 'Neue Belegvorlage hinzufügen',
   'Add note'                    => 'Notiz erfassen',
   'Add part'                    => 'Artikel hinzufügen',
+  'Add part classification'     => 'Artikel-Klassifizierung hinzufügen',
   'Add partsgroup'              => 'Warengruppe hinzufügen',
   'Add picture'                 => 'Bild hinzufügen',
   'Add picture to text block'   => 'Bild dem Textblock hinzufügen',
@@ -667,7 +668,6 @@ $self->{texts} = {
   'Create a new delivery term'  => 'Neue Lieferbedingungen anlegen',
   'Create a new department'     => 'Eine neue Abteilung erfassen',
   'Create a new group'          => 'Neue Benutzergruppe erfassen',
-  'Create a new parts classification' => 'Erzeuge eine neue Artikel-Klassifizierung',
   'Create a new payment term'   => 'Neue Zahlungsbedingungen anlegen',
   'Create a new predefined text' => 'Einen neuen vordefinierten Textblock anlegen',
   'Create a new price rule'     => 'Neue Preisregel anlegen',
@@ -1126,7 +1126,7 @@ $self->{texts} = {
   'Edit general settings'       => 'Grundeinstellungen bearbeiten',
   'Edit greetings'              => 'Anreden bearbeiten',
   'Edit note'                   => 'Notiz bearbeiten',
-  'Edit parts classification'   => 'Bearbeite eine Artikel-Klassifizierung',
+  'Edit part classification'    => 'Artikel-Klassifizierung bearbeiten',
   'Edit partsgroup'             => 'Warengruppe bearbeiten',
   'Edit payment term'           => 'Zahlungsbedingungen bearbeiten',
   'Edit picture'                => 'Bild bearbeiten',
@@ -1885,7 +1885,6 @@ $self->{texts} = {
   'No invoices have been selected.' => 'Es wurden keine Rechnungen ausgewählt.',
   'No or an unknown authenticantion module specified in "config/kivitendo.conf".' => 'Es wurde kein oder ein unbekanntes Authentifizierungsmodul in "config/kivitendo.conf" angegeben.',
   'No part was selected.'       => 'Es wurde kein Artikel ausgewählt',
-  'No parts classification has been created yet.' => 'Keine Artikel-Klassifizierung erzeugt.',
   'No payment term has been created yet.' => 'Es wurden noch keine Zahlungsbedingungen angelegt.',
   'No picture has been uploaded' => 'Es wurde kein Bild hochgeladen',
   'No picture uploaded yet'     => 'Noch kein Bild hochgeladen',
@@ -2075,6 +2074,7 @@ $self->{texts} = {
   'Part Number missing!'        => 'Artikelnummer fehlt!',
   'Part Type'                   => 'Artikel-Typ',
   'Part Unit'                   => 'Einheit des Artikels',
+  'Part classifications'        => 'Artikel-Klassifizierungen',
   'Part picker'                 => 'Artikelauswahl',
   'PartClassAbbreviation'       => 'Abkürzung der Artikel-Klassifizierung',
   'Part_br_Description'         => 'Beschreibung',
@@ -2082,7 +2082,6 @@ $self->{texts} = {
   'Partnumber'                  => 'Artikelnummer',
   'Parts'                       => 'Waren',
   'Parts Classification'        => 'Artikel-Klassifizierung',
-  'Parts Classifications'       => 'Artikel-Klassifizierung',
   'Parts Inventory'             => 'Warenliste',
   'Parts Master Data'           => 'Artikelstammdaten',
   'Parts with existing part numbers' => 'Artikel mit existierender Artikelnummer',
@@ -2924,7 +2923,6 @@ $self->{texts} = {
   'The base unit does not exist.' => 'Die Basiseinheit existiert nicht.',
   '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.',
   '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.',
-  'The basic parts classification cannot be deleted.' => 'Eine Basis Artikel-Klassifizierung darf nicht gelöscht werden.',
   'The body is missing.'        => 'Der Text fehlt',
   'The booking group has been created.' => 'Die Buchungsgruppe wurde erstellt.',
   'The booking group has been deleted.' => 'Die Buchungsgruppe wurde gelöscht.',
@@ -3066,10 +3064,6 @@ $self->{texts} = {
   'The partnumber already exists!' => 'Die Artikelnummer wird bereits verwendet.',
   'The partnumber already exists.' => 'Die Artikelnummer wird bereits verwndet.',
   'The partnumber is missing.'  => 'Die Artikelnummer fehlt.',
-  'The parts classification has been created.' => 'Die Artikel-Klassifizierung ist erzeugt',
-  'The parts classification has been deleted.' => 'Die Artikel-Klassifizierung ist gelöscht',
-  'The parts classification has been saved.' => 'Die Artikel-Klassifizierung ist gespeichert',
-  'The parts classification is in use and cannot be deleted.' => 'Die Artikel-Klassifizierung ist in Verwendung, kann deshalb nicht gelöscht werden.',
   'The parts for this delivery order have already been transferred in.' => 'Die Artikel dieses Lieferscheins wurden bereits eingelagert.',
   'The parts for this delivery order have already been transferred out.' => 'Die Artikel dieses Lieferscheins wurden bereits ausgelagert.',
   'The parts have been removed.' => 'Die Waren wurden aus dem Lager entnommen.',
@@ -3378,6 +3372,7 @@ $self->{texts} = {
   'Trying to call a sub without a name' => 'Es wurde versucht, eine Unterfunktion ohne Namen aufzurufen.',
   'TypAbbreviation'             => 'Abkürzung des Artikel-Typs',
   'Type'                        => 'Typ',
+  'Type abbreviation'           => 'Typen-Abkürzung',
   'Type can be either \'part\', \'service\' or \'assembly\'.' => 'Der Typ kann entweder \'part\' (für Waren), \'service\' (für Dienstleistungen) oder \'assembly\' (für Erzeugnisse) enthalten.',
   'Type of Business'            => 'Kunden-/Lieferantentyp',
   'Type of Customer'            => 'Kundentyp',
diff --git a/menus/user/00-erp.yaml b/menus/user/00-erp.yaml
index d1f54c21f..84490b4a7 100644
--- a/menus/user/00-erp.yaml
+++ b/menus/user/00-erp.yaml
@@ -1080,7 +1080,8 @@
   icon: partsclassific
   order: 1100
   params:
-    action: PartClassification/list
+    action: SimpleSystemSetting/list
+    type: part_classification
 - parent: system
   id: system_pricegroups
   name: Pricegroups
diff --git a/templates/webpages/part_classification/form.html b/templates/webpages/part_classification/form.html
deleted file mode 100755
index 2725df2fe..000000000
--- a/templates/webpages/part_classification/form.html
+++ /dev/null
@@ -1,41 +0,0 @@
-[% USE HTML %][% USE L %][% USE LxERP %]
-<h1>[% FORM.title %]</h1>
-
- <form method="post" action="controller.pl">
-
-[%- INCLUDE 'common/flash.html' %]
-
-  <table>
-   <tr>
-    <td>[% LxERP.t8('Description') %]</td>
-    <td>[% L.input_tag("part_classification.description",  LxERP.t8(SELF.part_classification.description)) %]</td>
-   </tr>
-   <tr>
-    <td>[% LxERP.t8('TypeAbbreviation') %]</td>
-    <td>[% L.input_tag("part_classification.abbreviation",  LxERP.t8(SELF.part_classification.abbreviation),size=>"2",maxlength=>"2" ) %]</td>
-   </tr>
-   <tr>
-    <td>[% LxERP.t8('Used for Purchase') %]</td>
-    <td>[% L.checkbox_tag("part_classification.used_for_purchase", checked=(SELF.part_classification.used_for_purchase ? 1:'')) %]</td>
-   </tr>
-   <tr>
-    <td>[% LxERP.t8('Used for Sale') %]</td>
-    <td>[% L.checkbox_tag("part_classification.used_for_sale", checked=(SELF.part_classification.used_for_sale ? 1:'')) %]</td>
-   </tr>
-   <tr>
-    <td>[% LxERP.t8('Report separately') %]</td>
-    <td>[% L.checkbox_tag("part_classification.report_separate", checked=(SELF.part_classification.report_separate ? 1:'')) %]</td>
-   </tr>
-  </table>
-
-  <p>
-   [% L.hidden_tag("id", SELF.part_classification.id) %]
-   [% L.hidden_tag("action", "PartClassification/dispatch") %]
-   [% L.submit_tag("action_" _ (SELF.part_classification.id ? 'update' : 'create'), LxERP.t8('Save')) %]
-   [%- IF SELF.part_classification.id %]
-    [% L.submit_tag("action_destroy", LxERP.t8('Delete'), confirm=LxERP.t8('Do you really want to delete this object?')) %]
-   [%- END %]
-   <a href="[% SELF.url_for(action => 'list') %]">[% LxERP.t8('Abort') %]</a>
-  </p>
-
- </form>
diff --git a/templates/webpages/part_classification/list.html b/templates/webpages/part_classification/list.html
deleted file mode 100644
index f7bb1c26c..000000000
--- a/templates/webpages/part_classification/list.html
+++ /dev/null
@@ -1,49 +0,0 @@
-[% USE HTML %][% USE L %][% USE LxERP %]
-<h1>[% FORM.title %]</h1>
-
-[%- INCLUDE 'common/flash.html' %]
-
- <form method="post" action="controller.pl">
-  [% IF !PART_CLASSIFICATIONS.size %]
-   <p>
-    [%-  LxERP.t8('No parts classification has been created yet.') %]
-   </p>
-
-  [%- ELSE %]
-   <table id="part_classification_list">
-    <thead>
-    <tr class="listheading">
-     <th align="center"><img src="image/updown.png" alt="[%- LxERP.t8('reorder item') %]"></th>
-     <th>[%- LxERP.t8('Description') %]</th>
-     <th>[%- LxERP.t8('TypeAbbreviation') %]</th>
-     <th>[%- LxERP.t8('Used for Purchase') %]</th>
-     <th>[%- LxERP.t8('Used for Sale') %]</th>
-     <th>[%- LxERP.t8('Report separately') %]</th>
-    </tr>
-    </thead>
-
-    <tbody>
-    [%- FOREACH part_classification = PART_CLASSIFICATIONS %]
-    <tr class="listrow[% loop.count % 2 %]" id="part_classification_id_[% part_classification.id %]">
-     <td align="center" class="dragdrop"><img src="image/updown.png" alt="[%- LxERP.t8('reorder item') %]"></td>
-     <td>
-      <a href="[% SELF.url_for(action => 'edit', id => part_classification.id) %]">
-       [%- HTML.escape(LxERP.t8(part_classification.description)) %]
-      </a>
-     </td>
-     <td>[%- HTML.escape(LxERP.t8(part_classification.abbreviation)) %]</td>
-     <td>[% IF part_classification.used_for_purchase %][% LxERP.t8('Yes') %][% ELSE %][%  LxERP.t8('No') %][% END %]</td>
-     <td>[% IF part_classification.used_for_sale     %][% LxERP.t8('Yes') %][% ELSE %][%  LxERP.t8('No') %][% END %]</td>
-     <td>[% IF part_classification.report_separate   %][% LxERP.t8('Yes') %][% ELSE %][%  LxERP.t8('No') %][% END %]</td>
-    </tr>
-    [%- END %]
-    </tbody>
-   </table>
-  [%- END %]
-
-  <p>
-   <a href="[% SELF.url_for(action => 'new') %]">[%- LxERP.t8('Create a new parts classification') %]</a>
-  </p>
- </form>
-
- [% L.sortable_element('#part_classification_list tbody', url => 'controller.pl?action=PartClassification/reorder', with => 'part_classification_id') %]
diff --git a/templates/webpages/simple_system_setting/_part_classification_form.html b/templates/webpages/simple_system_setting/_part_classification_form.html
new file mode 100644
index 000000000..309f67c26
--- /dev/null
+++ b/templates/webpages/simple_system_setting/_part_classification_form.html
@@ -0,0 +1,23 @@
+[%- USE LxERP -%][%- USE L -%]
+<table>
+ <tr>
+  <th align="right">[% LxERP.t8('Description') %]</th>
+  <td>[% L.input_tag("object.description",  LxERP.t8(SELF.object.description), "data-validate"="required", "data-title"=LxERP.t8("Description")) %]</td>
+ </tr>
+ <tr>
+  <th align="right">[% LxERP.t8('TypeAbbreviation') %]</th>
+  <td>[% L.input_tag("object.abbreviation",  LxERP.t8(SELF.object.abbreviation), size="2", maxlength="2" ) %]</td>
+ </tr>
+ <tr>
+  <th align="right">[% LxERP.t8('Used for Purchase') %]</th>
+  <td>[% L.checkbox_tag("object.used_for_purchase", checked=(SELF.object.used_for_purchase ? 1:''), for_submit=1) %]</td>
+ </tr>
+ <tr>
+  <th align="right">[% LxERP.t8('Used for Sale') %]</th>
+  <td>[% L.checkbox_tag("object.used_for_sale", checked=(SELF.object.used_for_sale ? 1:''), for_submit=1) %]</td>
+ </tr>
+ <tr>
+  <th align="right">[% LxERP.t8('Report separately') %]</th>
+  <td>[% L.checkbox_tag("object.report_separate", checked=(SELF.object.report_separate ? 1:''), for_submit=1) %]</td>
+ </tr>
+</table>
