commit 9c5f94c0359a8f2c0dba93b5e9bdef99f332fcc8
Author: Moritz Bunkus <m.bunkus@linet.de>
Date:   Tue Apr 19 10:43:43 2016 +0200

    Wiederkerende Rechnungen: Konfiguration für automatischen Versand via E-Mail

diff --git a/SL/DB/MetaSetup/PeriodicInvoicesConfig.pm b/SL/DB/MetaSetup/PeriodicInvoicesConfig.pm
index 0c0545384..9cb9998af 100644
--- a/SL/DB/MetaSetup/PeriodicInvoicesConfig.pm
+++ b/SL/DB/MetaSetup/PeriodicInvoicesConfig.pm
@@ -9,21 +9,27 @@ use parent qw(SL::DB::Object);
 __PACKAGE__->meta->table('periodic_invoices_configs');
 
 __PACKAGE__->meta->columns(
-  active                  => { type => 'boolean', default => 'true' },
-  ar_chart_id             => { type => 'integer', not_null => 1 },
-  copies                  => { type => 'integer' },
-  direct_debit            => { type => 'boolean', default => 'false', not_null => 1 },
-  end_date                => { type => 'date' },
-  extend_automatically_by => { type => 'integer' },
-  first_billing_date      => { type => 'date' },
-  id                      => { type => 'integer', not_null => 1, sequence => 'id' },
-  oe_id                   => { type => 'integer', not_null => 1 },
-  order_value_periodicity => { type => 'varchar', length => 1, not_null => 1 },
-  periodicity             => { type => 'varchar', length => 1, not_null => 1 },
-  print                   => { type => 'boolean', default => 'false' },
-  printer_id              => { type => 'integer' },
-  start_date              => { type => 'date' },
-  terminated              => { type => 'boolean', default => 'false' },
+  active                     => { type => 'boolean', default => 'true' },
+  ar_chart_id                => { type => 'integer', not_null => 1 },
+  copies                     => { type => 'integer' },
+  direct_debit               => { type => 'boolean', default => 'false', not_null => 1 },
+  email_body                 => { type => 'text' },
+  email_recipient_address    => { type => 'text' },
+  email_recipient_contact_id => { type => 'integer' },
+  email_sender               => { type => 'text' },
+  email_subject              => { type => 'text' },
+  end_date                   => { type => 'date' },
+  extend_automatically_by    => { type => 'integer' },
+  first_billing_date         => { type => 'date' },
+  id                         => { type => 'integer', not_null => 1, sequence => 'id' },
+  oe_id                      => { type => 'integer', not_null => 1 },
+  order_value_periodicity    => { type => 'varchar', length => 1, not_null => 1 },
+  periodicity                => { type => 'varchar', length => 1, not_null => 1 },
+  print                      => { type => 'boolean', default => 'false' },
+  printer_id                 => { type => 'integer' },
+  send_email                 => { type => 'boolean', default => 'false', not_null => 1 },
+  start_date                 => { type => 'date' },
+  terminated                 => { type => 'boolean', default => 'false' },
 );
 
 __PACKAGE__->meta->primary_key_columns([ 'id' ]);
@@ -34,6 +40,11 @@ __PACKAGE__->meta->foreign_keys(
     key_columns => { ar_chart_id => 'id' },
   },
 
+  email_recipient_contact => {
+    class       => 'SL::DB::Contact',
+    key_columns => { email_recipient_contact_id => 'cp_id' },
+  },
+
   order => {
     class       => 'SL::DB::Order',
     key_columns => { oe_id => 'id' },
diff --git a/SL/OE.pm b/SL/OE.pm
index 0282f569e..7a045bfcb 100644
--- a/SL/OE.pm
+++ b/SL/OE.pm
@@ -805,7 +805,7 @@ sub load_periodic_invoice_config {
 
     if ($config_obj) {
       my $config = { map { $_ => $config_obj->$_ } qw(active terminated periodicity order_value_periodicity start_date_as_date end_date_as_date first_billing_date_as_date extend_automatically_by ar_chart_id
-                                                      print printer_id copies direct_debit) };
+                                                      print printer_id copies direct_debit send_email email_recipient_contact_id email_recipient_address email_sender email_subject email_body) };
       $form->{periodic_invoices_config} = YAML::Dump($config);
     }
   }
diff --git a/bin/mozilla/oe.pl b/bin/mozilla/oe.pl
index 131f3f817..5755e1a47 100644
--- a/bin/mozilla/oe.pl
+++ b/bin/mozilla/oe.pl
@@ -2077,6 +2077,10 @@ sub edit_periodic_invoices_config {
   $::form->{AR}    = [ grep { $_->{link} =~ m/(?:^|:)AR(?::|$)/ } @{ $::form->{ALL_CHARTS} } ];
   $::form->{title} = $::locale->text('Edit the configuration for periodic invoices');
 
+  if ($::form->{customer_id}) {
+    $::form->{ALL_CONTACTS} = SL::DB::Manager::Contact->get_all_sorted(where => [ cp_cv_id => $::form->{customer_id} ]);
+  }
+
   $::form->header(no_layout => 1);
   print $::form->parse_html_template('oe/edit_periodic_invoices_config', $config);
 
@@ -2105,6 +2109,12 @@ sub save_periodic_invoices_config {
                  copies                  => $::form->{copies} * 1 ? $::form->{copies} : 1,
                  extend_automatically_by => $::form->{extend_automatically_by} * 1 || undef,
                  ar_chart_id             => $::form->{ar_chart_id} * 1,
+                 send_email                 => $::form->{send_email} ? 1 : 0,
+                 email_recipient_contact_id => $::form->{email_recipient_contact_id} * 1 || undef,
+                 email_recipient_address    => $::form->{email_recipient_address},
+                 email_sender               => $::form->{email_sender},
+                 email_subject              => $::form->{email_subject},
+                 email_body                 => $::form->{email_body},
                };
 
   $::form->{periodic_invoices_config} = YAML::Dump($config);
@@ -2214,4 +2224,3 @@ sub dispatcher {
 
   $::form->error($::locale->text('No action defined.'));
 }
-
diff --git a/css/kivitendo/main.css b/css/kivitendo/main.css
index 9c5ea64c5..fc6b38fd9 100644
--- a/css/kivitendo/main.css
+++ b/css/kivitendo/main.css
@@ -73,6 +73,11 @@ hr {
 	height: 2px;
 }
 
+tr.rule-before th, tr.rule-before td {
+  padding-top: 2px;
+  border-top: 2px solid #EBEBEB;
+}
+
 /* I.E. & Chrome können das nicht! */
 /* input[type="radio"], input[type="checkbox"]{
 	width:1.15em;
diff --git a/js/edit_periodic_invoices_config.js b/js/edit_periodic_invoices_config.js
index b969e1dde..775f58418 100644
--- a/js/edit_periodic_invoices_config.js
+++ b/js/edit_periodic_invoices_config.js
@@ -1,13 +1,15 @@
 function edit_periodic_invoices_config() {
-  var width     = 750;
-  var height    = 550;
+  var width     = 800;
+  var height    = 650;
   var parm      = centerParms(width, height) + ",width=" + width + ",height=" + height + ",status=yes,scrollbars=yes";
 
   var config    = $('#periodic_invoices_config').val();
+  var cus_id    = $('[name=customer_id]').val();
   var transdate = $('#transdate').val();
 
   var url       = "oe.pl?" +
     "action=edit_periodic_invoices_config&" +
+    "customer_id="              + encodeURIComponent(cus_id) + "&" +
     "periodic_invoices_config=" + encodeURIComponent(config) + "&" +
     "transdate="                + encodeURIComponent(transdate || '');
 
diff --git a/locale/de/all b/locale/de/all
index abcbacfbe..1fe9ed759 100755
--- a/locale/de/all
+++ b/locale/de/all
@@ -595,6 +595,7 @@ $self->{texts} = {
   'Contact is in use and was flagged invalid.' => 'Die Ansprechperson ist noch in Verwendung und wurde deshalb nur als ungültig markiert.',
   'Contact person (surname)'    => 'Ansprechperson (Nachname)',
   'Contact persons'             => 'Ansprechpersonen',
+  'Contact to send to'          => 'An Ansprechperson schicken',
   'Contacts'                    => 'Ansprechpersonen',
   'Content'                     => 'Inhalt',
   'Continue'                    => 'Weiter',
@@ -1704,6 +1705,7 @@ $self->{texts} = {
   'More than one #1 found matching, please be more specific.' => 'Mehr als ein #1 wurde gefunden, bitte geben Sie den Namen genauer an.',
   'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
   'Multi mode not supported.'   => 'Multimodus wird nicht unterstützt.',
+  'Multiple addresses can be entered separated by commas.' => 'Mehrere Adressen können durch Kommata getrennt angegeben werden.',
   'MwSt. inkl.'                 => 'MwSt. inkl.',
   'Name'                        => 'Name',
   'Name and Street'             => 'Name und Straße',
@@ -1912,6 +1914,7 @@ $self->{texts} = {
   'Orphaned'                    => 'Nie benutzt',
   'Orphaned currencies'         => 'Verwaiste Währungen',
   'Other Matches'               => 'Andere Treffer',
+  'Other recipients'            => 'Weitere EmpfängerInnen',
   'Other users\' follow-ups'    => 'Wiedervorlagen anderer Benutzer',
   'Other values are ignored.'   => 'Andere Eingaben werden ignoriert.',
   'Others'                      => 'Andere',
@@ -2448,6 +2451,7 @@ $self->{texts} = {
   'Sellprice for price group \'#1\'' => 'Verkaufspreis für Preisgruppe \'#1\'',
   'Sellprice significant places' => 'Verkaufspreis: Nachkommastellen',
   'Semicolon'                   => 'Semikolon',
+  'Send invoice via email'      => 'Rechnung via E-Mail verschicken',
   'Send letter via e-mail'      => 'Brief via E-Mail verschicken',
   'Sender'                      => 'AbsenderIn',
   'Sending E-mail: '            => 'E-Mail versenden: ',
diff --git a/scripts/rose_auto_create_model.pl b/scripts/rose_auto_create_model.pl
index 9334934ae..fd43a0506 100755
--- a/scripts/rose_auto_create_model.pl
+++ b/scripts/rose_auto_create_model.pl
@@ -73,7 +73,7 @@ our %foreign_key_name_map     = (
     follow_ups                => { created_for_user => 'created_for_employee', created_by => 'created_by_employee', },
     follow_up_access          => { who => 'with_access', what => 'to_follow_ups_by', },
 
-    periodic_invoices_configs => { oe_id => 'order' },
+    periodic_invoices_configs => { oe_id => 'order', email_recipient_contact_id => 'email_recipient_contact' },
     reconciliation_links      => { acc_trans_id => 'acc_trans' },
   },
 );
diff --git a/sql/Pg-upgrade2/periodic_invoices_send_email.sql b/sql/Pg-upgrade2/periodic_invoices_send_email.sql
new file mode 100644
index 000000000..91eab25ec
--- /dev/null
+++ b/sql/Pg-upgrade2/periodic_invoices_send_email.sql
@@ -0,0 +1,18 @@
+-- @tag: periodic_invoices_send_email
+-- @description: Wiederkehrende Rechnungen automatisch per E-Mail verschicken
+-- @depends: release_3_4_0
+ALTER TABLE periodic_invoices_configs ADD COLUMN send_email                 BOOLEAN;
+ALTER TABLE periodic_invoices_configs ADD COLUMN email_recipient_contact_id INTEGER;
+ALTER TABLE periodic_invoices_configs ADD COLUMN email_recipient_address    TEXT;
+ALTER TABLE periodic_invoices_configs ADD COLUMN email_sender               TEXT;
+ALTER TABLE periodic_invoices_configs ADD COLUMN email_subject              TEXT;
+ALTER TABLE periodic_invoices_configs ADD COLUMN email_body                 TEXT;
+
+UPDATE periodic_invoices_configs SET send_email = FALSE;
+
+ALTER TABLE periodic_invoices_configs ALTER COLUMN send_email SET DEFAULT FALSE;
+ALTER TABLE periodic_invoices_configs ALTER COLUMN send_email SET NOT NULL;
+
+ALTER TABLE periodic_invoices_configs
+ADD FOREIGN KEY (email_recipient_contact_id) REFERENCES contacts (cp_id)
+ON DELETE SET NULL;
diff --git a/templates/webpages/oe/edit_periodic_invoices_config.html b/templates/webpages/oe/edit_periodic_invoices_config.html
index 8ee4952af..63cc7fa1c 100644
--- a/templates/webpages/oe/edit_periodic_invoices_config.html
+++ b/templates/webpages/oe/edit_periodic_invoices_config.html
@@ -77,7 +77,7 @@
      <td valign="top">[% L.checkbox_tag("direct_debit", checked=direct_debit) %]</td>
     </tr>
 
-    <tr>
+    <tr class="rule-before">
      <th align="right">[%- LxERP.t8('Print automatically') %]</th>
      <td valign="top">
       [% L.checkbox_tag("print", onclick => "toggle_printer_id_ctrl()", checked => print) %]
@@ -95,6 +95,36 @@
      <th align="right">[%- LxERP.t8('Copies') %]</th>
      <td valign="top">[% L.input_tag("copies", copies, size => 6, disabled => !print) %]</td>
     </tr>
+
+    <tr class="rule-before">
+     <th align="right">[%- LxERP.t8("Send invoice via email") %]</th>
+     <td>[% L.checkbox_tag("send_email", onclick => "toggle_send_email_ctrl()", checked=send_email) %]</td>
+    </tr>
+
+    <tr>
+     <th align="right">[%- LxERP.t8("Contact to send to") %]</th>
+     <td>[% L.select_tag("email_recipient_contact_id", ALL_CONTACTS, title_key="full_name_dep", value_key="cp_id", default=email_recipient_contact_id, with_empty=1, disabled=!send_email, style=style) %]</td>
+    </tr>
+
+    <tr>
+     <th align="right">[%- LxERP.t8("Other recipients") %]<sup>3</sup></th>
+     <td>[% L.input_tag("email_recipient_address", email_recipient_address, disabled=!send_email, style=style) %]</td>
+    </tr>
+
+    <tr>
+     <th align="right">[%- LxERP.t8("Sender") %]</th>
+     <td>[% L.input_tag("email_sender", email_sender, disabled=!send_email, style=style) %]</td>
+    </tr>
+
+    <tr>
+     <th align="right">[%- LxERP.t8("Subject") %]</th>
+     <td>[% L.input_tag("email_subject", email_subject, disabled=!send_email, style=style) %]</td>
+    </tr>
+
+    <tr>
+     <th align="right" valign="top">[%- LxERP.t8("Message") %]</th>
+     <td valign="top">[% L.textarea_tag("email_body", email_body, disabled=!send_email, rows=8, style=style) %]</td>
+    </tr>
    </table>
   </p>
 
@@ -102,6 +132,7 @@
 
   <p>(1): [%- LxERP.t8('The end date is the last day for which invoices will possibly be created.') %]</p>
   <p>(2): [% LxERP.t8("If missing then the start date will be used.") %]</p>
+  <p>(3): [% LxERP.t8("Multiple addresses can be entered separated by commas.") %]</p>
 
   [% L.hidden_tag('action', 'save_periodic_invoices_config') %]
 
@@ -118,5 +149,14 @@
       $('#printer_id').prop('disabled', disabled);
       $('#copies').prop('disabled', disabled);
     }
+
+    function toggle_send_email_ctrl() {
+      var disabled = !$('#send_email').prop('checked');
+      $('#email_recipient_contact_id').prop('disabled', disabled);
+      $('#email_recipient_address').prop('disabled', disabled);
+      $('#email_from').prop('disabled', disabled);
+      $('#email_subject').prop('disabled', disabled);
+      $('#email_body').prop('disabled', disabled);
+    }
     -->
  </script>
