Auftragsschnellerfassung: Währung und Wechselkurs definierbar
authorFelix Eichler <felix.eichler@opendynamic.de>
Thu, 21 Mar 2019 09:34:51 +0000 (10:34 +0100)
committerBernd Bleßmann <bernd@kivitendo-premium.de>
Mon, 27 Jul 2020 10:16:05 +0000 (12:16 +0200)
impl. #9491

(cherry picked from commit 6cdc5a4a33df4530ce4e141151e83138320e27a2)
(cherry pick von odyn)

SL/Controller/Order.pm
SL/DB/Order.pm
js/kivi.Order.js
js/locale/de.js
js/locale/en.js
templates/webpages/order/tabs/basic_data.html

index 689c597..5419847 100644 (file)
@@ -926,6 +926,18 @@ sub action_recalc_amounts_and_taxes {
   $self->js->render();
 }
 
+sub action_update_exchangerate {
+  my ($self) = @_;
+  my $data = {};
+  if ($self->order->currency_id != $::instance_conf->get_currency_id) {
+    $data = {
+      currency_name => $self->order->currency->name,
+      exchangerate  => $self->order->exchangerate_as_number,
+    };
+  }
+  $self->render(\SL::JSON::to_json($data), { type => 'json', process => 0 });
+}
+
 # redisplay item rows if they are sorted by an attribute
 sub action_reorder_items {
   my ($self) = @_;
@@ -1509,8 +1521,7 @@ sub setup_order_from_cv {
 sub recalc {
   my ($self) = @_;
 
-  # bb: todo: currency later
-  $self->order->currency_id($::instance_conf->get_currency_id());
+  $self->order->currency_id($::instance_conf->get_currency_id()) unless $self->order->currency_id;
 
   my %pat = $self->order->calculate_prices_and_taxes();
 
@@ -1657,6 +1668,7 @@ sub pre_render {
   my ($self) = @_;
 
   $self->{all_taxzones}               = SL::DB::Manager::TaxZone->get_all_sorted();
+  $self->{all_currencies}             = SL::DB::Manager::Currency->get_all_sorted();
   $self->{all_departments}            = SL::DB::Manager::Department->get_all_sorted();
   $self->{all_employees}              = SL::DB::Manager::Employee->get_all(where => [ or => [ id => $self->order->employee_id,
                                                                                               deleted => 0 ] ],
index 3732242..98a8c5a 100644 (file)
@@ -10,6 +10,7 @@ use List::MoreUtils qw(any);
 
 use SL::DB::MetaSetup::Order;
 use SL::DB::Manager::Order;
+use SL::DB::Helper::Attr;
 use SL::DB::Helper::AttrHTML;
 use SL::DB::Helper::AttrSorted;
 use SL::DB::Helper::FlattenToForm;
@@ -40,8 +41,15 @@ __PACKAGE__->meta->add_relationship(
     column_map             => { id => 'trans_id' },
     query_args             => [ module => 'OE' ],
   },
+  exchangerate_obj         => {
+    type                   => 'one to one',
+    class                  => 'SL::DB::Exchangerate',
+    column_map             => { currency_id => 'currency_id', transdate => 'transdate' },
+  },
 );
 
+SL::DB::Helper::Attr::make(__PACKAGE__, exchangerate => 'numeric');
+
 __PACKAGE__->meta->initialize;
 
 __PACKAGE__->attr_html('notes');
@@ -111,6 +119,30 @@ sub is_sales {
   return !!shift->customer_id;
 }
 
+sub exchangerate {
+  my ($self, $val) = @_;
+
+  return 1 if $self->currency_id == $::instance_conf->get_currency_id;
+
+  my $rate = $self->is_sales ? 'buy' : 'sell';
+
+  if (defined $val) {
+    croak 'exchange rate has to be positive' if $val <= 0;
+    if (!$self->exchangerate_obj) {
+      $self->exchangerate_obj(SL::DB::Exchangerate->new(
+        currency_id => $self->currency_id,
+        transdate   => $self->transdate,
+        $rate       => $val,
+      ));
+    } elsif (!defined $self->exchangerate_obj->$rate) {
+      $self->exchangerate_obj->$rate($val);
+    } else {
+      croak 'exchange rate already exists, no update allowed';
+    }
+  }
+  return $self->exchangerate_obj->$rate if $self->exchangerate_obj;
+}
+
 sub invoices {
   my $self   = shift;
   my %params = @_;
index e4cebb2..682a14b 100644 (file)
@@ -174,6 +174,42 @@ namespace('kivi.Order', function(ns) {
     $(event.target).val(kivi.format_amount(kivi.parse_amount($(event.target).val()), -2));
   };
 
+  ns.update_exchangerate = function(event) {
+    var rate_input = $('#order_exchangerate_as_number');
+    rate_input.attr('name', '');
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'Order/update_exchangerate' });
+
+    $.ajax({
+      url: 'controller.pl',
+      data: data,
+      method: 'POST',
+      dataType: 'json',
+      success: function(data){
+        if (data.currency_name) {
+          $('#currency_name').text(data.currency_name);
+          var rate_text = $('#exchangerate_text');
+          if (data.exchangerate) {
+            rate_text.text(data.exchangerate);
+            rate_input.hide();
+          } else {
+            rate_text.text('');
+            rate_input.show().attr('name', rate_input.data('name')).val(0);
+          }
+          $('#exchangerate_settings').show();
+        } else {
+          $('#exchangerate_settings').hide();
+        }
+        if ($('#order_currency_id').val() != $('#old_currency_id').val() || data.exchangerate != $('#old_exchangerate').val()) {
+          kivi.display_flash('warning', kivi.t8('You have changed the currency. Please update prices.'));
+        }
+        $('#old_currency_id').val($('#order_currency_id').val());
+        $('#old_exchangerate').val(data.exchangerate);
+      }
+    });
+  };
+
   ns.recalc_amounts_and_taxes = function() {
     var data = $('#order_form').serializeArray();
     data.push({ name: 'action', value: 'Order/recalc_amounts_and_taxes' });
@@ -792,6 +828,9 @@ $(function() {
     $('#order_vendor_id').change(kivi.Order.reload_cv_dependent_selections);
   }
 
+  $('#order_currency_id').change(kivi.Order.update_exchangerate);
+  $('#order_transdate').change(kivi.Order.update_exchangerate);
+
   if ($('#type').val() == 'sales_order' || $('#type').val() == 'sales_quotation' ) {
     $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.sellprice, -2)) });
   } else {
index daad4ca..a69f517 100644 (file)
@@ -143,6 +143,7 @@ namespace("kivi").setupLocale({
 "Wrong number format (#1)":"Falsches Zahlenformat (#1)",
 "Wrong time format (#1)":"Falsches Zeitformat (#1)",
 "Yes":"Ja",
+"You have changed the currency. Please update prices.":"Währungswechsel/Kurswechsel haben Einfluss auf den Preis der Position. Überprüfen Sie diesen oder aktualisieren Sie den Preis über \"Artikel aktualisieren\".",
 "filename has not uploadable characters ":"Bitte Dateinamen ändern. Er hat für den Upload nicht verwendbare Sonderzeichen ",
 "filesize too big: ":"Datei zu groß: ",
 "flat-rate position":"Pauschalposition",
index 87bc1b7..428e9b7 100644 (file)
@@ -143,6 +143,7 @@ namespace("kivi").setupLocale({
 "Wrong number format (#1)":"",
 "Wrong time format (#1)":"",
 "Yes":"",
+"You have changed the currency. Please update prices.":"",
 "filename has not uploadable characters ":"",
 "filesize too big: ":"",
 "flat-rate position":"",
index 698ef63..c54b8f3 100644 (file)
             <td>[% L.select_tag('order.taxzone_id', SELF.all_taxzones, default=SELF.order.taxzone_id, title_key='description', style='width: 300px', class='recalc') %]</td>
           </tr>
 
+          <tr id="currency_settings">
+            <th align="right">[% 'Currency' | $T8 %]</th>
+            <td>[% L.select_tag('order.currency_id', SELF.all_currencies, default=SELF.order.currency_id, value_key='id', title_key='name') %]</td>
+          </tr>
+          <tr id="exchangerate_settings" [%- IF !SELF.order.currency_id || SELF.order.currency_id==INSTANCE_CONF.get_currency_id %]style='display:none'[%- END %]>
+            <th align="right">[% 'Exchangerate' | $T8 %]</th>
+            <td> 1 <span id="currency_name">[% SELF.order.currency.name %]</span> =
+              <span id="exchangerate_text">
+              [% IF SELF.order.exchangerate %]
+                [% HTML.escape(SELF.order.exchangerate_as_number) %]
+              [% END %]
+              </span>
+              [% IF !SELF.order.currency_id || SELF.order.currency_id==INSTANCE_CONF.get_currency_id || SELF.order.exchangerate %]
+                [% L.input_tag('', '', size="15", id='order_exchangerate_as_number', 'data-name'='order.exchangerate_as_number', style='display:none') %]
+              [% ELSE %]
+                [% L.input_tag('order.exchangerate_as_number', 0, size="15") %]
+              [% END %]
+              [% INSTANCE_CONF.default_currency %]
+              [% L.hidden_tag('old_currency_id', SELF.order.currency_id) %]
+              [% L.hidden_tag('old_exchangerate', SELF.order.exchangerate_as_number) %]
+            </td>
+          </tr>
+
 [%- IF SELF.all_departments.size %]
           <tr>
             <th align="right">[% 'Department' | $T8 %]</th>