commit 35b3d155b05ffc994cc4e3cf4eeaa457a6650501
Author: Geoffrey Richardson <information@kivitendo-premium.de>
Date:   Sun Aug 7 22:30:45 2016 +0200

    Neuen Artikeltyp Sortiment eingeführt - sql und rose

diff --git a/SL/DB/AssortmentItem.pm b/SL/DB/AssortmentItem.pm
new file mode 100644
index 000000000..1f53f969f
--- /dev/null
+++ b/SL/DB/AssortmentItem.pm
@@ -0,0 +1,28 @@
+# This file has been auto-generated only because it didn't exist.
+# Feel free to modify it at will; it will not be overwritten automatically.
+
+package SL::DB::AssortmentItem;
+
+use strict;
+
+use SL::DB::MetaSetup::AssortmentItem;
+use SL::DB::Manager::AssortmentItem;
+use Rose::DB::Object::Helpers qw(clone);
+
+__PACKAGE__->meta->initialize;
+
+sub linetotal {
+  my ($self) = @_;
+
+  return 0 unless $self->qty > 0 and $self->part->sellprice > 0;
+  return $self->qty * $self->part->sellprice / ( $self->part->price_factor_id ? $self->part->price_factor->factor : 1 );
+}
+
+sub linetotal_lastcost {
+  my ($self) = @_;
+
+  return 0 unless $self->qty > 0 and $self->part->lastcost > 0;
+  return $self->qty * $self->part->lastcost / ( $self->part->price_factor_id ? $self->part->price_factor->factor : 1 );
+}
+
+1;
diff --git a/SL/DB/Helper/ALL.pm b/SL/DB/Helper/ALL.pm
index da11bb47f..bf6bd40df 100644
--- a/SL/DB/Helper/ALL.pm
+++ b/SL/DB/Helper/ALL.pm
@@ -4,6 +4,7 @@ use strict;
 
 use SL::DB::AccTransaction;
 use SL::DB::Assembly;
+use SL::DB::AssortmentItem;
 use SL::DB::AuthClient;
 use SL::DB::AuthClientUser;
 use SL::DB::AuthClientGroup;
diff --git a/SL/DB/Helper/Mappings.pm b/SL/DB/Helper/Mappings.pm
index 738a93c90..7d1907dfa 100644
--- a/SL/DB/Helper/Mappings.pm
+++ b/SL/DB/Helper/Mappings.pm
@@ -99,6 +99,7 @@ my %kivitendo_package_names = (
   ar                             => 'invoice',
   ap                             => 'purchase_invoice',
   assembly                       => 'assembly',
+  assortment_items               => 'assortment_item',
   background_jobs                => 'background_job',
   background_job_histories       => 'background_job_history',
   ap                             => 'purchase_invoice',
diff --git a/SL/DB/Manager/AssortmentItem.pm b/SL/DB/Manager/AssortmentItem.pm
new file mode 100644
index 000000000..1b0cb6021
--- /dev/null
+++ b/SL/DB/Manager/AssortmentItem.pm
@@ -0,0 +1,14 @@
+# This file has been auto-generated only because it didn't exist.
+# Feel free to modify it at will; it will not be overwritten automatically.
+
+package SL::DB::Manager::AssortmentItem;
+
+use strict;
+
+use parent qw(SL::DB::Helper::Manager);
+
+sub object_class { 'SL::DB::AssortmentItem' }
+
+__PACKAGE__->make_manager_methods;
+
+1;
diff --git a/SL/DB/MetaSetup/AssortmentItem.pm b/SL/DB/MetaSetup/AssortmentItem.pm
new file mode 100644
index 000000000..5cedfbfa9
--- /dev/null
+++ b/SL/DB/MetaSetup/AssortmentItem.pm
@@ -0,0 +1,43 @@
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::AssortmentItem;
+
+use strict;
+
+use parent qw(SL::DB::Object);
+
+__PACKAGE__->meta->table('assortment_items');
+
+__PACKAGE__->meta->columns(
+  assortment_id => { type => 'integer', not_null => 1 },
+  itime         => { type => 'timestamp', default => 'now()' },
+  mtime         => { type => 'timestamp' },
+  parts_id      => { type => 'integer', not_null => 1 },
+  position      => { type => 'integer', not_null => 1 },
+  qty           => { type => 'float', not_null => 1, scale => 4 },
+  unit          => { type => 'varchar', length => 20, not_null => 1 },
+);
+
+__PACKAGE__->meta->primary_key_columns([ 'assortment_id', 'parts_id' ]);
+
+__PACKAGE__->meta->allow_inline_column_values(1);
+
+__PACKAGE__->meta->foreign_keys(
+  assortment => {
+    class       => 'SL::DB::Part',
+    key_columns => { assortment_id => 'id' },
+  },
+
+  part => {
+    class       => 'SL::DB::Part',
+    key_columns => { parts_id => 'id' },
+  },
+
+  unit_obj => {
+    class       => 'SL::DB::Unit',
+    key_columns => { unit => 'name' },
+  },
+);
+
+1;
+;
diff --git a/SL/DB/MetaSetup/Default.pm b/SL/DB/MetaSetup/Default.pm
index 775961593..9d7eeaaba 100644
--- a/SL/DB/MetaSetup/Default.pm
+++ b/SL/DB/MetaSetup/Default.pm
@@ -24,6 +24,7 @@ __PACKAGE__->meta->columns(
   ar_show_mark_as_paid                      => { type => 'boolean', default => 'true' },
   articlenumber                             => { type => 'text' },
   assemblynumber                            => { type => 'text' },
+  assortmentnumber                          => { type => 'text' },
   balance_startdate_method                  => { type => 'text' },
   bin_id                                    => { type => 'integer' },
   bin_id_ignore_onhand                      => { type => 'integer' },
diff --git a/SL/DB/Part.pm b/SL/DB/Part.pm
index d6ffc3547..8b149ad4c 100644
--- a/SL/DB/Part.pm
+++ b/SL/DB/Part.pm
@@ -38,6 +38,11 @@ __PACKAGE__->meta->add_relationships(
     class        => 'SL::DB::Translation',
     column_map   => { id => 'parts_id' },
   },
+  assortment_items => {
+    type         => 'one to many',
+    class        => 'SL::DB::AssortmentItem',
+    column_map   => { id => 'assortment_id' },
+  },
 );
 
 __PACKAGE__->meta->initialize;
diff --git a/doc/changelog b/doc/changelog
index 2b77b59a5..a9f5efc56 100644
--- a/doc/changelog
+++ b/doc/changelog
@@ -45,6 +45,25 @@ kleinere neue Features und Detailverbesserungen:
     Verkaufsauträge finden zu können:
     Verkauf -> Berichte -> Auftragsartikelsuche
 
+  - Neuer Artikeltyp "Sortiment"
+    Einem Sortiment	können wie einem Erzeugnis mehrere Artikel zugeordnet
+    werden. Beim Hinzufügen eines Sortiments zu einem Beleg werden alle
+    Bestandteile des Sortiments als Einzelteile zum Beleg hinzugefügt, so als
+    ob man das manuell gemacht hätte. Der Sortimentsartikel wird ohne Preis
+    hinzugefügt und fungiert als Überschrift, und kann sogar gelöscht werden.
+    Nach dem Hinzufügen können die Einzelbestandteile auch gelöscht oder
+    verändert werden. Dadurch hat das Sortiment auch keinen festen Preis,
+    sondern der Preis im Beleg richtet sich nach dem Preis der
+    Einzelbestandteile, die je nach Kunde z.B. durch Preisgruppenpreise
+    variieren können.
+
+    Das Sortiment eignet sich z.B. als Definition von Gruppierungen von
+    Artikeln die häufig zusammen gekauft werden, z.B. ein Artikel in 10
+    Farbvariationen.
+
+    Einschränkungen: das "Auspacken" eines Sortiments beim Hinzufügen in einem
+    Beleg funktioniert derzeit nur beim neuen Auftragscontroller.
+
 Administrative Änderungen
 
   - Diverse Textsuchen werden jetzt durch eine neue Klasse Indizes
diff --git a/scripts/rose_auto_create_model.pl b/scripts/rose_auto_create_model.pl
index 2604fcefa..5d311c18e 100755
--- a/scripts/rose_auto_create_model.pl
+++ b/scripts/rose_auto_create_model.pl
@@ -82,6 +82,7 @@ our %foreign_key_name_map     = (
     reconciliation_links      => { acc_trans_id => 'acc_trans' },
 
     assembly                  => { parts_id => 'part', id => 'assembly_part' },
+    assortment_items          => { parts_id => 'part' },
   },
 );
 
diff --git a/sql/Pg-upgrade2/assortment.sql b/sql/Pg-upgrade2/assortment.sql
new file mode 100644
index 000000000..5d9c68598
--- /dev/null
+++ b/sql/Pg-upgrade2/assortment.sql
@@ -0,0 +1,20 @@
+-- @tag: assortment_items
+-- @description: Sortimentsartikel eingeführt
+-- @depends: release_3_4_1 part_type_enum
+
+-- adding a new value isn't allowed inside a transaction, which is what DBUpgrade automatically does
+-- run this afterwards manually for now
+-- ALTER TYPE part_type_enum ADD VALUE 'assortment';
+
+CREATE TABLE assortment_items (
+  assortment_id INTEGER REFERENCES parts(id) ON DELETE CASCADE, -- the part id of the assortment
+  parts_id      INTEGER REFERENCES parts(id),
+  itime         timestamp without time zone default now(),
+  mtime         timestamp without time zone,
+  qty           REAL NOT NULL,
+  position      INTEGER NOT NULL,
+  unit          character varying(20) NOT NULL REFERENCES units(name),
+  CONSTRAINT assortment_part_pkey PRIMARY KEY (assortment_id, parts_id)
+);
+
+ALTER TABLE defaults ADD assortmentnumber TEXT;
diff --git a/templates/webpages/client_config/_ranges_of_numbers.html b/templates/webpages/client_config/_ranges_of_numbers.html
index 51b11b943..a7cc99343 100644
--- a/templates/webpages/client_config/_ranges_of_numbers.html
+++ b/templates/webpages/client_config/_ranges_of_numbers.html
@@ -44,6 +44,8 @@
   <tr>
    <td align="right" nowrap>[% LxERP.t8('Last Sales Delivery Order Number') %]</td>
    <td>[% L.input_tag("defaults.sdonumber", SELF.defaults.sdonumber, size="15") %]</td>
+   <td align="right" nowrap>[% LxERP.t8('Last Assortment Number') %]</td>
+   <td>[% L.input_tag("defaults.assortmentnumber", SELF.defaults.assortmentnumber, size="15") %]</td>
   </tr>
 
   <tr>
