commit d3ae6850565e55743af3b9aadfb12f308a30ac94
Author: Werner Hahn <wh@futureworldsearch.net>
Date:   Fri Sep 22 02:23:52 2017 +0200

    WebshopApi: ShopImage

diff --git a/SL/DB/Helper/ALL.pm b/SL/DB/Helper/ALL.pm
index acc9f7e86..90ab85bf2 100644
--- a/SL/DB/Helper/ALL.pm
+++ b/SL/DB/Helper/ALL.pm
@@ -116,6 +116,7 @@ use SL::DB::SepaExportItem;
 use SL::DB::SepaExportMessageId;
 use SL::DB::Shipto;
 use SL::DB::Shop;
+use SL::DB::ShopImage;
 use SL::DB::ShopOrder;
 use SL::DB::ShopOrderItem;
 use SL::DB::ShopPart;
diff --git a/SL/DB/Helper/Mappings.pm b/SL/DB/Helper/Mappings.pm
index c1327f5fb..ac4b0617a 100644
--- a/SL/DB/Helper/Mappings.pm
+++ b/SL/DB/Helper/Mappings.pm
@@ -196,6 +196,7 @@ my %kivitendo_package_names = (
   schema_info                    => 'schema_info',
   shipto                         => 'shipto',
   shops                          => 'shop',
+  shop_images                    => 'shop_image',
   shop_orders                    => 'shop_order',
   shop_order_items               => 'shop_order_item',
   shop_parts                     => 'shop_part',
diff --git a/SL/DB/Manager/ShopImage.pm b/SL/DB/Manager/ShopImage.pm
new file mode 100644
index 000000000..5d597d91c
--- /dev/null
+++ b/SL/DB/Manager/ShopImage.pm
@@ -0,0 +1,15 @@
+# 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::ShopImage;
+
+use strict;
+
+use parent qw(SL::DB::Helper::Manager);
+use SL::DB::Helper::Sorted;
+
+sub object_class { 'SL::DB::ShopImage' }
+
+__PACKAGE__->make_manager_methods;
+
+1;
diff --git a/SL/DB/MetaSetup/Default.pm b/SL/DB/MetaSetup/Default.pm
index f62f1d1fd..ea81e3504 100644
--- a/SL/DB/MetaSetup/Default.pm
+++ b/SL/DB/MetaSetup/Default.pm
@@ -55,6 +55,7 @@ __PACKAGE__->meta->columns(
   doc_storage_for_attachments               => { type => 'text', default => 'Filesystem' },
   doc_storage_for_documents                 => { type => 'text', default => 'Filesystem' },
   doc_storage_for_images                    => { type => 'text', default => 'Filesystem' },
+  doc_storage_for_shopimages                => { type => 'text', default => 'Filesystem' },
   doc_webdav                                => { type => 'boolean', default => 'false' },
   dunning_ar                                => { type => 'integer' },
   dunning_ar_amount_fee                     => { type => 'integer' },
diff --git a/SL/DB/MetaSetup/ShopImage.pm b/SL/DB/MetaSetup/ShopImage.pm
new file mode 100644
index 000000000..3182840bf
--- /dev/null
+++ b/SL/DB/MetaSetup/ShopImage.pm
@@ -0,0 +1,36 @@
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::ShopImage;
+
+use strict;
+
+use parent qw(SL::DB::Object);
+
+__PACKAGE__->meta->table('shop_images');
+
+__PACKAGE__->meta->columns(
+  file_id                => { type => 'integer' },
+  id                     => { type => 'serial', not_null => 1 },
+  itime                  => { type => 'timestamp', default => 'now()' },
+  mtime                  => { type => 'timestamp' },
+  object_id              => { type => 'text', not_null => 1 },
+  org_file_height        => { type => 'integer' },
+  org_file_width         => { type => 'integer' },
+  position               => { type => 'integer' },
+  thumbnail_content      => { type => 'bytea' },
+  thumbnail_content_type => { type => 'text' },
+);
+
+__PACKAGE__->meta->primary_key_columns([ 'id' ]);
+
+__PACKAGE__->meta->allow_inline_column_values(1);
+
+__PACKAGE__->meta->foreign_keys(
+  file => {
+    class       => 'SL::DB::File',
+    key_columns => { file_id => 'id' },
+  },
+);
+
+1;
+;
diff --git a/SL/DB/ShopImage.pm b/SL/DB/ShopImage.pm
new file mode 100644
index 000000000..b95a55cfa
--- /dev/null
+++ b/SL/DB/ShopImage.pm
@@ -0,0 +1,16 @@
+# 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::ShopImage;
+
+use strict;
+
+use SL::DB::MetaSetup::ShopImage;
+use SL::DB::Manager::ShopImage;
+use SL::DB::Helper::ActsAsList;
+
+__PACKAGE__->meta->initialize;
+
+__PACKAGE__->configure_acts_as_list(group_by => [qw(object_id)]);
+
+1;
diff --git a/sql/Pg-upgrade2/shopimages.sql b/sql/Pg-upgrade2/shopimages.sql
new file mode 100644
index 000000000..8a61bb9c2
--- /dev/null
+++ b/sql/Pg-upgrade2/shopimages.sql
@@ -0,0 +1,34 @@
+-- @tag:shopimages
+-- @description: Tabelle für Shopbilder und zusätzliche Konfiguration und valid_type für Filemanagement
+-- @charset: UTF-8
+-- @depends: release_3_5_0 files shop_parts
+-- @ignore: 0
+
+CREATE TABLE shop_images(
+  id                      SERIAL PRIMARY KEY,
+  file_id                 INTEGER REFERENCES files(id) ON DELETE CASCADE,
+  position                INTEGER,
+  thumbnail_content       BYTEA,
+  thumbnail_width         INTEGER,
+  thumbnail_height        INTEGER,
+  thumbnail_content_type  TEXT,
+  itime                   TIMESTAMP DEFAULT now(),
+  mtime                   TIMESTAMP
+);
+
+CREATE TRIGGER mtime_shop_images BEFORE UPDATE ON shop_images FOR EACH ROW EXECUTE PROCEDURE set_mtime();
+
+ALTER TABLE defaults ADD COLUMN doc_storage_for_shopimages      text default 'Filesystem';
+
+ALTER TABLE files
+  DROP CONSTRAINT valid_type;
+ALTER TABLE files
+  ADD  CONSTRAINT valid_type CHECK (
+             (object_type = 'credit_note'     ) OR (object_type = 'invoice'                 ) OR (object_type = 'sales_order'       )
+          OR (object_type = 'sales_quotation' ) OR (object_type = 'sales_delivery_order'    ) OR (object_type = 'request_quotation' )
+          OR (object_type = 'purchase_order'  ) OR (object_type = 'purchase_delivery_order' ) OR (object_type = 'purchase_invoice'  )
+          OR (object_type = 'vendor'          ) OR (object_type = 'customer'                ) OR (object_type = 'part'              )
+          OR (object_type = 'gl_transaction'  ) OR (object_type = 'dunning'                 ) OR (object_type = 'dunning1'          )
+          OR (object_type = 'dunning2'        ) OR (object_type = 'dunning3'                ) OR (object_type = 'draft'             )
+          OR (object_type = 'statement'       ) OR (object_type = 'shop_image'              )
+  );
diff --git a/sql/Pg-upgrade2/shopimages_2.sql b/sql/Pg-upgrade2/shopimages_2.sql
new file mode 100644
index 000000000..9609b7b29
--- /dev/null
+++ b/sql/Pg-upgrade2/shopimages_2.sql
@@ -0,0 +1,8 @@
+-- @tag:shopimages_2
+-- @description: Umbennung der Spalten für Weite und Breite in die Weite und Breite des orginal Bildes
+-- @charset: UTF-8
+-- @depends: release-3.5.0 files shop_parts shopimages
+-- @ignore: 0
+
+ALTER TABLE shop_images RENAME thumbnail_width TO org_file_width;
+ALTER TABLE shop_images RENAME thumbnail_height TO org_file_height;
diff --git a/sql/Pg-upgrade2/shopimages_3.sql b/sql/Pg-upgrade2/shopimages_3.sql
new file mode 100644
index 000000000..7ffd86748
--- /dev/null
+++ b/sql/Pg-upgrade2/shopimages_3.sql
@@ -0,0 +1,7 @@
+-- @tag:shopimages_3
+-- @description: Neue Spalte object_id um eine group_by Klausel zu haben für act_as_list
+-- @charset: UTF-8
+-- @depends: release_3_5_0 files shop_parts shopimages
+-- @ignore: 0
+
+ALTER TABLE shop_images ADD COLUMN object_id text NOT NULL;
diff --git a/templates/webpages/client_config/_features.html b/templates/webpages/client_config/_features.html
index 752471299..48b1ba307 100644
--- a/templates/webpages/client_config/_features.html
+++ b/templates/webpages/client_config/_features.html
@@ -58,6 +58,14 @@
                                onchange="return checkavailable_filebackend(this);") %]</td>
     <td>[% LxERP.t8('Use this storage backend for uploaded images') %]</td>
   </tr>
+  <tr>
+    <td align="right">[% LxERP.t8('Storage Type for shopimages') %]</td>
+    <td>[% L.select_tag('defaults.doc_storage_for_shopimages',
+         [ [ 'None', LxERP.t8('None') ], [ 'Filesystem', LxERP.t8('Files') ],[ 'Webdav', LxERP.t8('WebDAV') ],[ 'ExtDMS', LxERP.t8('ext.DMS') ],[ 'DB', LxERP.t8('Database') ]  ],
+                               default = SELF.defaults.doc_storage_for_shopimages,
+                               onchange="return checkavailable_filebackend(this);") %]</td>
+    <td>[% LxERP.t8('Use this storage backend for uploaded images') %]</td>
+  </tr>
   <tr>
    <td align="right">[% LxERP.t8('Delete printfiles') %]</td>
    <td>[% L.yes_no_tag('defaults.doc_delete_printfiles', SELF.defaults.doc_delete_printfiles) %]</td>
