Uebernahme der kompletten Version, so wie sie Philip als "Demo-Version" gezeigt hat...
[kivitendo-erp.git] / SL / IS.pm
index e29f67f..686f864 100644 (file)
--- a/SL/IS.pm
+++ b/SL/IS.pm
@@ -35,6 +35,7 @@
 package IS;
 
 use Data::Dumper;
+use SL::AM;
 
 sub invoice_details {
   $main::lxdebug->enter_sub();
@@ -67,7 +68,6 @@ sub invoice_details {
   for $i (1 .. $form->{rowcount}) {
     $partsgroup = "";
     if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
-      $form->format_string("partsgroup_$i");
       $partsgroup = $form->{"partsgroup_$i"};
     }
     push @partsgroup, [$i, $partsgroup];
@@ -81,6 +81,14 @@ sub invoice_details {
   my $taxamount;
   my $taxbase;
   my $taxdiff;
+  my $nodiscount;
+  my $yesdiscount;
+  my $nodiscount_subtotal = 0;
+  my $discount_subtotal = 0;
+  my $position = 0;
+  my $subtotal_header = 0;
+  my $subposition = 0;
+
 
   foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
     $i = $item->[0];
@@ -97,13 +105,27 @@ sub invoice_details {
 
     if ($form->{"qty_$i"} != 0) {
 
-      # add number, description and qty to $form->{number}, ....
-      push(@{ $form->{runningnumber} }, $i);
+      # add number, description and qty to $form->{number},
+      if ($form->{"subtotal_$i"} && !$subtotal_header) {
+        $subtotal_header = $i;
+        $position = int($position);
+        $subposition = 0;
+        $position++;
+      } elsif ($subtotal_header) {
+        $subposition += 1;
+        $position = int($position);
+        $position = $position.".".$subposition;
+      } else {
+        $position = int($position);
+        $position++;
+      }
+      push(@{ $form->{runningnumber} }, $position);
       push(@{ $form->{number} },        qq|$form->{"partnumber_$i"}|);
       push(@{ $form->{serialnumber} },  qq|$form->{"serialnumber_$i"}|);
       push(@{ $form->{bin} },           qq|$form->{"bin_$i"}|);
       push(@{ $form->{"partnotes"} },   qq|$form->{"partnotes_$i"}|);
       push(@{ $form->{description} },   qq|$form->{"description_$i"}|);
+      push(@{ $form->{longdescription} },   qq|$form->{"longdescription_$i"}|);
       push(@{ $form->{qty} },
            $form->format_amount($myconfig, $form->{"qty_$i"}));
       push(@{ $form->{unit} },            qq|$form->{"unit_$i"}|);
@@ -112,6 +134,8 @@ sub invoice_details {
       push(@{ $form->{sellprice} },    $form->{"sellprice_$i"});
       push(@{ $form->{ordnumber_oe} }, qq|$form->{"ordnumber_$i"}|);
       push(@{ $form->{transdate_oe} }, qq|$form->{"transdate_$i"}|);
+      push(@{ $form->{invnumber} }, qq|$form->{"invnumber"}|);
+      push(@{ $form->{invdate} }, qq|$form->{"invdate"}|);
 
       if ($form->{lizenzen}) {
         if ($form->{"licensenumber_$i"}) {
@@ -162,6 +186,9 @@ sub invoice_details {
       my $linetotal =
         $form->round_amount($form->{"qty_$i"} * $form->{"netprice_$i"}, 2);
 
+      my $nodiscount_linetotal =
+        $form->round_amount($form->{"qty_$i"} * $sellprice, 2);
+
       $discount =
         ($discount != 0)
         ? $form->format_amount($myconfig, $discount * -1, $decimalplaces)
@@ -170,12 +197,39 @@ sub invoice_details {
 
       push(@{ $form->{discount} },   $discount);
       push(@{ $form->{p_discount} }, $form->{"discount_$i"});
-
+      if (($form->{"discount_$i"} ne "") && ($form->{"discount_$i"} != 0)) {
+        $form->{discount_p} = $form->{"discount_$i"};
+      }
       $form->{total} += $linetotal;
+      $discount_subtotal += $linetotal;
+      $form->{nodiscount_total} += $nodiscount_linetotal;
+      $nodiscount_subtotal += $nodiscount_linetotal;
+      $form->{discount_total} += $form->parse_amount($myconfig, $discount);
+
+      if ($form->{"subtotal_$i"} && $subtotal_header && ($subtotal_header != $i)) {
+        $discount_subtotal = $form->format_amount($myconfig, $discount_subtotal, 2);
+        push(@{ $form->{discount_sub} },  $discount_subtotal);
+        $nodiscount_subtotal = $form->format_amount($myconfig, $nodiscount_subtotal, 2);
+        push(@{ $form->{nodiscount_sub} }, $nodiscount_subtotal);
+        $discount_subtotal = 0;
+        $nodiscount_subtotal = 0;
+        $subtotal_header = 0;
+      } else {
+        push(@{ $form->{discount_sub} }, "");
+        push(@{ $form->{nodiscount_sub} }, "");
+      }
+
+      if ($linetotal == $netto_linetotal) {
+        $nodiscount += $linetotal;
+      }
 
       push(@{ $form->{linetotal} },
            $form->format_amount($myconfig, $linetotal, 2));
+      push(@{ $form->{nodiscount_linetotal} },
+           $form->format_amount($myconfig, $nodiscount_linetotal, 2));
+
 
+      
       @taxaccounts = split / /, $form->{"taxaccounts_$i"};
       $taxrate     = 0;
       $taxdiff     = 0;
@@ -247,20 +301,19 @@ sub invoice_details {
         while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
           if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
             map { push(@{ $form->{$_} }, "") }
-              qw(runningnumber number serialnumber unit qty bin sellprice listprice netprice discount linetotal);
+              qw(runningnumber number serialnumber unit qty bin sellprice listprice netprice discount linetotal nodiscount_linetotal);
             $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
             push(@{ $form->{description} }, $sameitem);
           }
 
           map { $form->{"a_$_"} = $ref->{$_} } qw(partnumber description);
-          $form->format_string("a_partnumber", "a_description");
 
           push(@{ $form->{description} },
                $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}
                  )
                  . qq| -- $form->{"a_partnumber"}, $form->{"a_description"}|);
           map { push(@{ $form->{$_} }, "") }
-            qw(number unit qty runningnumber serialnumber bin sellprice listprice netprice discount linetotal);
+            qw(number unit qty runningnumber serialnumber bin sellprice listprice netprice discount linetotal nodiscount_linetotal);
 
         }
         $sth->finish;
@@ -269,18 +322,16 @@ sub invoice_details {
   }
 
   foreach my $item (sort keys %taxaccounts) {
-    if ($form->round_amount($taxaccounts{$item}, 2) != 0) {
-      push(@{ $form->{taxbase} },
-           $form->format_amount($myconfig, $taxbase{$item}, 2));
+    push(@{ $form->{taxbase} },
+          $form->format_amount($myconfig, $taxbase{$item}, 2));
 
-      $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
+    $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
 
-      push(@{ $form->{tax} }, $form->format_amount($myconfig, $taxamount, 2));
-      push(@{ $form->{taxdescription} }, $form->{"${item}_description"});
-      push(@{ $form->{taxrate} },
-           $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
-      push(@{ $form->{taxnumber} }, $form->{"${item}_taxnumber"});
-    }
+    push(@{ $form->{tax} }, $form->format_amount($myconfig, $taxamount, 2));
+    push(@{ $form->{taxdescription} }, $form->{"${item}_description"});
+    push(@{ $form->{taxrate} },
+          $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
+    push(@{ $form->{taxnumber} }, $form->{"${item}_taxnumber"});
   }
 
   for my $i (1 .. $form->{paidaccounts}) {
@@ -296,12 +347,18 @@ sub invoice_details {
   }
 
   $form->{subtotal} = $form->format_amount($myconfig, $form->{total}, 2);
+  $yesdiscount = $form->{nodiscount_total} - $nodiscount;
+  $form->{nodiscount_subtotal} = $form->format_amount($myconfig, $form->{nodiscount_total}, 2);
+  $form->{discount_total} = $form->format_amount($myconfig, $form->{discount_total}, 2);
+  $form->{nodiscount} = $form->format_amount($myconfig, $nodiscount, 2);
+  $form->{yesdiscount} = $form->format_amount($myconfig, $yesdiscount, 2);
+
   $form->{invtotal} =
     ($form->{taxincluded}) ? $form->{total} : $form->{total} + $tax;
   $form->{total} =
     $form->format_amount($myconfig, $form->{invtotal} - $form->{paid}, 2);
   $form->{invtotal} = $form->format_amount($myconfig, $form->{invtotal}, 2);
-
+  $form->set_payment_options($myconfig, $form->{invdate});
   $form->{paid} = $form->format_amount($myconfig, $form->{paid}, 2);
 
   $form->{username} = $myconfig->{name};
@@ -340,7 +397,7 @@ sub customer_details {
   my $dbh = $form->dbconnect($myconfig);
 
   # get contact id, set it if nessessary
-  ($null, $form->{cp_id}) = split /--/, $form->{contact};
+  $form->{cp_id} *= 1;
 
   $contact = "";
   if ($form->{cp_id}) {
@@ -357,11 +414,36 @@ sub customer_details {
 
   $ref = $sth->fetchrow_hashref(NAME_lc);
 
-  # remove notes, id and taxincluded before copy back
-  delete @$ref{qw(id taxincluded notes)};
+  # remove id and taxincluded before copy back
+  delete @$ref{qw(id taxincluded)};
   map { $form->{$_} = $ref->{$_} } keys %$ref;
-
   $sth->finish;
+
+  if ($form->{delivery_customer_id}) {
+    my $query = qq|SELECT ct.*, ct.notes as customernotes
+                 FROM customer ct
+                WHERE ct.id = $form->{delivery_customer_id} limit 1|;
+    my $sth = $dbh->prepare($query);
+    $sth->execute || $form->dberror($query);
+
+    $ref = $sth->fetchrow_hashref(NAME_lc);
+
+    $sth->finish;
+    map { $form->{"dc_$_"} = $ref->{$_} } keys %$ref;
+  }
+
+  if ($form->{delivery_vendor_id}) {
+    my $query = qq|SELECT ct.*, ct.notes as customernotes
+                 FROM customer ct
+                WHERE ct.id = $form->{delivery_vendor_id} limit 1|;
+    my $sth = $dbh->prepare($query);
+    $sth->execute || $form->dberror($query);
+
+    $ref = $sth->fetchrow_hashref(NAME_lc);
+
+    $sth->finish;
+    map { $form->{"dv_$_"} = $ref->{$_} } keys %$ref;
+  }
   $dbh->disconnect;
 
   $main::lxdebug->leave_sub();
@@ -383,12 +465,25 @@ sub post_invoice {
     $form->get_employee($dbh);
   }
 
-  ($null, $form->{contact_id}) = split /--/, $form->{contact};
+  $form->{contact_id} = $form->{cp_id};
   $form->{contact_id} *= 1;
+  $form->{payment_id} *= 1;
+  $form->{language_id} *= 1;
+  $form->{taxzone_id} *= 1;
+  $form->{delivery_customer_id} *= 1;
+  $form->{delivery_vendor_id} *= 1;
+  $form->{storno} *= 1;
+  $form->{shipto_id} *= 1;
+
 
   ($null, $form->{department_id}) = split(/--/, $form->{department});
   $form->{department_id} *= 1;
 
+  my $service_units = AM->retrieve_units($myconfig,$form,"service");
+  my $part_units = AM->retrieve_units($myconfig,$form,"dimension");
+
+
+
   if ($form->{id}) {
 
     &reverse_invoice($dbh, $form);
@@ -435,10 +530,47 @@ sub post_invoice {
   $form->{expense_inventory} = "";
 
   foreach my $i (1 .. $form->{rowcount}) {
-    $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
+    if ($form->{type} eq "credit_note") {
+      $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"}) * -1;
+      $form->{shipped} = 1;   
+    } else {
+      $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
+    }
+    my $basefactor;
+    my $basqty;
+
+    if ($form->{storno}) {
+      $form->{"qty_$i"} *= -1;
+    }
 
     if ($form->{"qty_$i"} != 0) {
 
+      # get item baseunit
+      $query = qq|SELECT p.unit
+                  FROM parts p
+                  WHERE p.id = $form->{"id_$i"}|;
+      $sth = $dbh->prepare($query);
+      $sth->execute || $form->dberror($query);
+
+      my ($item_unit) = $sth->fetchrow_array();
+      $sth->finish;
+
+      if ($form->{"inventory_accno_$i"}) {
+        if (defined($part_units->{$item_unit}->{factor}) && $part_units->{$item_unit}->{factor} ne '' && $part_units->{$item_unit}->{factor} ne '0') {
+          $basefactor = $part_units->{$form->{"unit_$i"}}->{factor} / $part_units->{$item_unit}->{factor};
+        } else {
+          $basefactor = 1;
+        }
+        $baseqty = $form->{"qty_$i"} * $basefactor;
+      } else {
+        if (defined($service_units->{$item_unit}->{factor}) && $service_units->{$item_unit}->{factor} ne '' && $service_units->{$item_unit}->{factor} ne '0') {
+          $basefactor = $service_units->{$form->{"unit_$i"}}->{factor} / $service_units->{$item_unit}->{factor};
+        } else {
+          $basefactor = 1;
+        }
+        $baseqty = $form->{"qty_$i"} * $basefactor;
+      }
+
       map { $form->{"${_}_$i"} =~ s/\'/\'\'/g }
         (qw(partnumber description unit));
 
@@ -527,20 +659,20 @@ sub post_invoice {
           if ($sth->fetchrow_array) {
             $form->update_balance($dbh, "parts", "onhand",
                                   qq|id = $form->{"id_$i"}|,
-                                  $form->{"qty_$i"} * -1)
+                                  $baseqty * -1)
               unless $form->{shipped};
           }
           $sth->finish;
 
           # record assembly item as allocated
-          &process_assembly($dbh, $form, $form->{"id_$i"}, $form->{"qty_$i"});
+          &process_assembly($dbh, $form, $form->{"id_$i"}, $baseqty);
         } else {
           $form->update_balance($dbh, "parts", "onhand",
                                 qq|id = $form->{"id_$i"}|,
-                                $form->{"qty_$i"} * -1)
+                                $baseqty * -1)
             unless $form->{shipped};
 
-          $allocated = &cogs($dbh, $form, $form->{"id_$i"}, $form->{"qty_$i"});
+          $allocated = &cogs($dbh, $form, $form->{"id_$i"}, $baseqty, $basefactor);
         }
       }
 
@@ -556,19 +688,20 @@ sub post_invoice {
       # get pricegroup_id and save ist
       ($null, my $pricegroup_id) = split /--/, $form->{"sellprice_drag_$i"};
       $pricegroup_id *= 1;
+      my $subtotal = $form->{"subtotal_$i"} * 1;
 
       # save detail record in invoice table
-      $query = qq|INSERT INTO invoice (trans_id, parts_id, description, qty,
+      $query = qq|INSERT INTO invoice (trans_id, parts_id, description,longdescription, qty,
                   sellprice, fxsellprice, discount, allocated, assemblyitem,
                  unit, deliverydate, project_id, serialnumber, pricegroup_id,
-                 ordnumber, transdate, cusordnumber)
+                 ordnumber, transdate, cusordnumber, base_qty, subtotal)
                  VALUES ($form->{id}, $form->{"id_$i"},
-                 '$form->{"description_$i"}', $form->{"qty_$i"},
+                 '$form->{"description_$i"}', '$form->{"longdescription_$i"}', $form->{"qty_$i"},
                  $form->{"sellprice_$i"}, $fxsellprice,
                  $form->{"discount_$i"}, $allocated, 'f',
                  '$form->{"unit_$i"}', $deliverydate, (SELECT id from project where projectnumber = '$project_id'),
                  '$form->{"serialnumber_$i"}', '$pricegroup_id',
-                 '$form->{"ordnumber_$i"}', '$form->{"transdate_$i"}', '$form->{"cusordnumber_$i"}')|;
+                 '$form->{"ordnumber_$i"}', '$form->{"transdate_$i"}', '$form->{"cusordnumber_$i"}', $baseqty, '$subtotal')|;
       $dbh->do($query) || $form->dberror($query);
 
       if ($form->{lizenzen}) {
@@ -594,7 +727,11 @@ sub post_invoice {
 
   # total payments, don't move we need it here
   for my $i (1 .. $form->{paidaccounts}) {
-    $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
+    if ($form->{type} eq "credit_note") {
+      $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"}) * -1;
+    } else {
+      $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
+    }
     $form->{paid} += $form->{"paid_$i"};
     $form->{datepaid} = $form->{"datepaid_$i"} if ($form->{"datepaid_$i"});
   }
@@ -704,77 +841,79 @@ sub post_invoice {
   #  $form->{amount}{$form->{id}}{$form->{AR}} = 1 if ($form->{amount}{$form->{id}}{$form->{AR}} == 0);
 
   # record payments and offsetting AR
-  for my $i (1 .. $form->{paidaccounts}) {
-
-    if ($form->{"paid_$i"} != 0) {
-      my ($accno) = split /--/, $form->{"AR_paid_$i"};
-      $form->{"datepaid_$i"} = $form->{invdate}
-        unless ($form->{"datepaid_$i"});
-      $form->{datepaid} = $form->{"datepaid_$i"};
-
-      $exchangerate = 0;
-
-      if ($form->{currency} eq $form->{defaultcurrency}) {
-        $form->{"exchangerate_$i"} = 1;
-      } else {
-        $exchangerate =
-          $form->check_exchangerate($myconfig, $form->{currency},
-                                    $form->{"datepaid_$i"}, 'buy');
-
-        $form->{"exchangerate_$i"} =
-          ($exchangerate)
-          ? $exchangerate
-          : $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
-      }
-
-      # record AR
-      $amount =
-        $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $diff,
-                            2);
-
-      if ($form->{amount}{ $form->{id} }{ $form->{AR} } != 0) {
-        $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
-                   transdate)
-                   VALUES ($form->{id}, (SELECT c.id FROM chart c
-                                       WHERE c.accno = '$form->{AR}'),
-                   $amount, '$form->{"datepaid_$i"}')|;
+  if (!$form->{storno}) {
+    for my $i (1 .. $form->{paidaccounts}) {
+  
+      if ($form->{"paid_$i"} != 0) {
+        my ($accno) = split /--/, $form->{"AR_paid_$i"};
+        $form->{"datepaid_$i"} = $form->{invdate}
+          unless ($form->{"datepaid_$i"});
+        $form->{datepaid} = $form->{"datepaid_$i"};
+  
+        $exchangerate = 0;
+  
+        if ($form->{currency} eq $form->{defaultcurrency}) {
+          $form->{"exchangerate_$i"} = 1;
+        } else {
+          $exchangerate =
+            $form->check_exchangerate($myconfig, $form->{currency},
+                                      $form->{"datepaid_$i"}, 'buy');
+  
+          $form->{"exchangerate_$i"} =
+            ($exchangerate)
+            ? $exchangerate
+            : $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
+        }
+  
+        # record AR
+        $amount =
+          $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $diff,
+                              2);
+  
+        if ($form->{amount}{ $form->{id} }{ $form->{AR} } != 0) {
+          $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+                      transdate)
+                      VALUES ($form->{id}, (SELECT c.id FROM chart c
+                                          WHERE c.accno = '$form->{AR}'),
+                      $amount, '$form->{"datepaid_$i"}')|;
+          $dbh->do($query) || $form->dberror($query);
+        }
+  
+        # record payment
+        $form->{"paid_$i"} *= -1;
+  
+        $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
+                    source, memo)
+                    VALUES ($form->{id}, (SELECT c.id FROM chart c
+                                        WHERE c.accno = '$accno'),
+                    $form->{"paid_$i"}, '$form->{"datepaid_$i"}',
+                    '$form->{"source_$i"}', '$form->{"memo_$i"}')|;
         $dbh->do($query) || $form->dberror($query);
-      }
-
-      # record payment
-      $form->{"paid_$i"} *= -1;
-
-      $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
-                  source, memo)
-                  VALUES ($form->{id}, (SELECT c.id FROM chart c
-                                     WHERE c.accno = '$accno'),
-                 $form->{"paid_$i"}, '$form->{"datepaid_$i"}',
-                 '$form->{"source_$i"}', '$form->{"memo_$i"}')|;
-      $dbh->do($query) || $form->dberror($query);
-
-      # exchangerate difference
-      $form->{fx}{$accno}{ $form->{"datepaid_$i"} } +=
-        $form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) + $diff;
-
-      # gain/loss
-      $amount =
-        $form->{"paid_$i"} * $form->{exchangerate} - $form->{"paid_$i"} *
-        $form->{"exchangerate_$i"};
-      if ($amount > 0) {
-        $form->{fx}{ $form->{fxgain_accno} }{ $form->{"datepaid_$i"} } +=
-          $amount;
-      } else {
-        $form->{fx}{ $form->{fxloss_accno} }{ $form->{"datepaid_$i"} } +=
-          $amount;
-      }
-
-      $diff = 0;
-
-      # update exchange rate
-      if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
-        $form->update_exchangerate($dbh, $form->{currency},
-                                   $form->{"datepaid_$i"},
-                                   $form->{"exchangerate_$i"}, 0);
+  
+        # exchangerate difference
+        $form->{fx}{$accno}{ $form->{"datepaid_$i"} } +=
+          $form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) + $diff;
+  
+        # gain/loss
+        $amount =
+          $form->{"paid_$i"} * $form->{exchangerate} - $form->{"paid_$i"} *
+          $form->{"exchangerate_$i"};
+        if ($amount > 0) {
+          $form->{fx}{ $form->{fxgain_accno} }{ $form->{"datepaid_$i"} } +=
+            $amount;
+        } else {
+          $form->{fx}{ $form->{fxloss_accno} }{ $form->{"datepaid_$i"} } +=
+            $amount;
+        }
+  
+        $diff = 0;
+  
+        # update exchange rate
+        if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
+          $form->update_exchangerate($dbh, $form->{currency},
+                                    $form->{"datepaid_$i"},
+                                    $form->{"exchangerate_$i"}, 0);
+        }
       }
     }
   }
@@ -850,18 +989,41 @@ Message: $form->{message}\r| if $form->{message};
              taxincluded = '$form->{taxincluded}',
              curr = '$form->{currency}',
              department_id = $form->{department_id},
+             payment_id = $form->{payment_id},
+              type = '$form->{type}',
+             language_id = $form->{language_id},
+             taxzone_id = $form->{taxzone_id},
+             shipto_id = $form->{shipto_id},
+             delivery_customer_id = $form->{delivery_customer_id},
+             delivery_vendor_id = $form->{delivery_vendor_id},
              employee_id = $form->{employee_id},
+              storno = '$form->{storno}',
               cp_id = $form->{contact_id}
               WHERE id = $form->{id}
              |;
   $dbh->do($query) || $form->dberror($query);
 
+  if ($form->{storno}) {
+    $query = qq| update ar set paid=paid+amount where id=$form->{storno_id}|;
+    $dbh->do($query) || $form->dberror($query);
+    $query = qq| update ar set storno='$form->{storno}' where id=$form->{storno_id}|;
+    $dbh->do($query) || $form->dberror($query);
+    $query = qq§ update ar set intnotes='Rechnung storniert am $form->{invdate} ' || intnotes where id=$form->{storno_id}§;
+    $dbh->do($query) || $form->dberror($query);
+
+    $query = qq| update ar set paid=amount where id=$form->{id}|;
+    $dbh->do($query) || $form->dberror($query);
+  }
+
   $form->{pago_total} = $amount;
 
   # add shipto
   $form->{name} = $form->{customer};
   $form->{name} =~ s/--$form->{customer_id}//;
-  $form->add_shipto($dbh, $form->{id});
+
+  if (!$form->{shipto_id}) {
+    $form->add_shipto($dbh, $form->{id}, "AR");
+  }
 
   # save printed, emailed and queued
   $form->save_status($dbh);
@@ -878,6 +1040,150 @@ Message: $form->{message}\r| if $form->{message};
   return $rc;
 }
 
+sub post_payment {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $myconfig, $form, $locale) = @_;
+
+  # connect to database, turn off autocommit
+  my $dbh = $form->dbconnect_noauto($myconfig);
+
+  $form->{datepaid} = $form->{invdate};
+
+  # total payments, don't move we need it here
+  for my $i (1 .. $form->{paidaccounts}) {
+    if ($form->{type} eq "credit_note") {
+      $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"}) * -1;
+    } else {
+      $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
+    } 
+    $form->{paid} += $form->{"paid_$i"};
+    $form->{datepaid} = $form->{"datepaid_$i"} if ($form->{"datepaid_$i"});
+  }
+
+  $form->{exchangerate} =
+      $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate},
+                              "buy");
+
+  # record payments and offsetting AR
+  for my $i (1 .. $form->{paidaccounts}) {
+
+    if ($form->{"paid_$i"} != 0) {
+      my ($accno) = split /--/, $form->{"AR_paid_$i"};
+      $form->{"datepaid_$i"} = $form->{invdate}
+        unless ($form->{"datepaid_$i"});
+      $form->{datepaid} = $form->{"datepaid_$i"};
+
+      $exchangerate = 0;
+      if (($form->{currency} eq $form->{defaultcurrency}) || ($form->{defaultcurrency} eq "")) {
+        $form->{"exchangerate_$i"} = 1;
+      } else {
+        $exchangerate =
+          $form->check_exchangerate($myconfig, $form->{currency},
+                                    $form->{"datepaid_$i"}, 'buy');
+
+        $form->{"exchangerate_$i"} =
+          ($exchangerate)
+          ? $exchangerate
+          : $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
+      }
+
+      # record AR
+      $amount =
+        $form->round_amount($form->{"paid_$i"} * $form->{"exchangerate"},
+                            2);
+
+
+      $query = qq|DELETE FROM acc_trans WHERE trans_id=$form->{id} AND chart_id=(SELECT c.id FROM chart c
+                                      WHERE c.accno = '$form->{AR}') AND amount=$amount AND transdate='$form->{"datepaid_$i"}'|;
+      $dbh->do($query) || $form->dberror($query);
+
+      $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+                  transdate)
+                  VALUES ($form->{id}, (SELECT c.id FROM chart c
+                                      WHERE c.accno = '$form->{AR}'),
+                  $amount, '$form->{"datepaid_$i"}')|;
+      $dbh->do($query) || $form->dberror($query);
+
+
+      # record payment
+      $form->{"paid_$i"} *= -1;
+
+      $query = qq|DELETE FROM acc_trans WHERE trans_id=$form->{id} AND chart_id=(SELECT c.id FROM chart c
+                                      WHERE c.accno = '$accno') AND amount=$form->{"paid_$i"} AND transdate='$form->{"datepaid_$i"}' AND source='$form->{"source_$i"}' AND memo='$form->{"memo_$i"}'|;
+      $dbh->do($query) || $form->dberror($query);
+
+      $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
+                  source, memo)
+                  VALUES ($form->{id}, (SELECT c.id FROM chart c
+                                     WHERE c.accno = '$accno'),
+                 $form->{"paid_$i"}, '$form->{"datepaid_$i"}',
+                 '$form->{"source_$i"}', '$form->{"memo_$i"}')|;
+      $dbh->do($query) || $form->dberror($query);
+
+
+      # gain/loss
+      $amount =
+        $form->{"paid_$i"} * $form->{exchangerate} - $form->{"paid_$i"} *
+        $form->{"exchangerate_$i"};
+      if ($amount > 0) {
+        $form->{fx}{ $form->{fxgain_accno} }{ $form->{"datepaid_$i"} } +=
+          $amount;
+      } else {
+        $form->{fx}{ $form->{fxloss_accno} }{ $form->{"datepaid_$i"} } +=
+          $amount;
+      }
+
+      $diff = 0;
+
+      # update exchange rate
+      if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
+        $form->update_exchangerate($dbh, $form->{currency},
+                                   $form->{"datepaid_$i"},
+                                   $form->{"exchangerate_$i"}, 0);
+      }
+    }
+  }
+
+  # record exchange rate differences and gains/losses
+  foreach my $accno (keys %{ $form->{fx} }) {
+    foreach my $transdate (keys %{ $form->{fx}{$accno} }) {
+      if (
+          ($form->{fx}{$accno}{$transdate} =
+           $form->round_amount($form->{fx}{$accno}{$transdate}, 2)
+          ) != 0
+        ) {
+        $query = qq|DELETE FROM acc_trans WHERE trans_id=$form->{id} AND chart_id=(SELECT c.id FROM chart c
+                                        WHERE c.accno = '$accno') AND amount=$form->{fx}{$accno}{$transdate} AND transdate='$transdate' AND cleared='0' AND fx_transaction='1'|;
+        $dbh->do($query) || $form->dberror($query);
+        $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+                   transdate, cleared, fx_transaction)
+                   VALUES ($form->{id},
+                          (SELECT c.id FROM chart c
+                           WHERE c.accno = '$accno'),
+                   $form->{fx}{$accno}{$transdate}, '$transdate', '0', '1')|;
+        $dbh->do($query) || $form->dberror($query);
+      }
+    }
+  }
+  my $datepaid = ($form->{paid})    ? qq|'$form->{datepaid}'| : "NULL";
+
+  # save AR record
+  my $query = qq|UPDATE ar set
+              paid = $form->{paid},
+             datepaid = $datepaid
+              WHERE id=$form->{id}|;
+
+  $dbh->do($query) || $form->dberror($query);
+
+  my $rc = $dbh->commit;
+  $dbh->disconnect;
+
+  $main::lxdebug->leave_sub();
+
+  return $rc;
+}
+
 sub process_assembly {
   $main::lxdebug->enter_sub();
 
@@ -933,9 +1239,9 @@ sub process_assembly {
 sub cogs {
   $main::lxdebug->enter_sub();
 
-  my ($dbh, $form, $id, $totalqty) = @_;
+  my ($dbh, $form, $id, $totalqty, $basefactor) = @_;
 
-  my $query = qq|SELECT i.id, i.trans_id, i.qty, i.allocated, i.sellprice,
+  my $query = qq|SELECT i.id, i.trans_id, i.base_qty, i.allocated, i.sellprice,
                    (SELECT c.accno FROM chart c
                    WHERE p.inventory_accno_id = c.id) AS inventory_accno,
                   (SELECT c.accno FROM chart c
@@ -943,7 +1249,7 @@ sub cogs {
                  FROM invoice i, parts p
                  WHERE i.parts_id = p.id
                  AND i.parts_id = $id
-                 AND (i.qty + i.allocated) < 0
+                 AND (i.base_qty + i.allocated) < 0
                  ORDER BY trans_id|;
   my $sth = $dbh->prepare($query);
   $sth->execute || $form->dberror($query);
@@ -952,7 +1258,7 @@ sub cogs {
   my $qty;
 
   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
-    if (($qty = (($ref->{qty} * -1) - $ref->{allocated})) > $totalqty) {
+    if (($qty = (($ref->{base_qty} * -1) - $ref->{allocated})) > $totalqty) {
       $qty = $totalqty;
     }
 
@@ -961,7 +1267,7 @@ sub cogs {
 
     # total expenses and inventory
     # sellprice is the cost of the item
-    $linetotal = $form->round_amount($ref->{sellprice} * $qty, 2);
+    $linetotal = $form->round_amount(($ref->{sellprice} * $qty) / $basefactor, 2);
 
     if (!$eur) {
 
@@ -1062,7 +1368,7 @@ sub reverse_invoice {
   }
 
   $query = qq|DELETE FROM shipto
-              WHERE trans_id = $form->{id}|;
+              WHERE trans_id = $form->{id} AND module = 'AR'|;
   $dbh->do($query) || $form->dberror($query);
 
   $main::lxdebug->leave_sub();
@@ -1166,10 +1472,10 @@ sub retrieve_invoice {
 
     # retrieve invoice
     $query = qq|SELECT a.invnumber, a.ordnumber, a.quonumber, a.cusordnumber,
-                a.transdate AS invdate, a.deliverydate, a.paid,
-                a.shippingpoint, a.shipvia, a.terms, a.notes, a.intnotes,
-               a.duedate, a.taxincluded, a.curr AS currency,
-               a.employee_id, e.name AS employee
+                a.transdate AS invdate, a.deliverydate, a.paid, a.storno,
+                a.shippingpoint, a.shipvia, a.terms, a.notes, a.intnotes, a.taxzone_id,
+               a.duedate, a.taxincluded, a.curr AS currency, a.shipto_id, a.cp_id,
+               a.employee_id, e.name AS employee, a.payment_id, a.language_id, a.delivery_customer_id, a.delivery_vendor_id, a.type
                FROM ar a
                LEFT JOIN employee e ON (e.id = a.employee_id)
                WHERE a.id = $form->{id}|;
@@ -1183,17 +1489,33 @@ sub retrieve_invoice {
     $form->{exchangerate} =
       $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate},
                               "buy");
-
     # get shipto
     $query = qq|SELECT s.* FROM shipto s
-                WHERE s.trans_id = $form->{id}|;
+                WHERE s.trans_id = $form->{id} AND s.module = 'AR'|;
     $sth = $dbh->prepare($query);
     $sth->execute || $form->dberror($query);
 
     $ref = $sth->fetchrow_hashref(NAME_lc);
+    delete($ref->{id});
     map { $form->{$_} = $ref->{$_} } keys %$ref;
     $sth->finish;
 
+   if ($form->{delivery_customer_id}) {
+      $query = qq|SELECT name FROM customer WHERE id=$form->{delivery_customer_id}|;
+      $sth = $dbh->prepare($query);
+      $sth->execute || $form->dberror($query);
+      ($form->{delivery_customer_string}) = $sth->fetchrow_array();
+      $sth->finish;
+    }
+
+    if ($form->{delivery_vendor_id}) {
+      $query = qq|SELECT name FROM customer WHERE id=$form->{delivery_vendor_id}|;
+      $sth = $dbh->prepare($query);
+      $sth->execute || $form->dberror($query);
+      ($form->{delivery_vendor_string}) = $sth->fetchrow_array();
+      $sth->finish;
+    }
+
     # get printed, emailed
     $query = qq|SELECT s.printed, s.emailed, s.spoolfile, s.formname
                 FROM status s
@@ -1210,34 +1532,71 @@ sub retrieve_invoice {
     $sth->finish;
     map { $form->{$_} =~ s/ +$//g } qw(printed emailed queued);
 
+    my $transdate = "current_date";
+    if($form->{invdate}) {
+     $transdate = "'$form->{invdate}'";
+    }
+
+    if(!$form->{taxzone_id}) {
+      $form->{taxzone_id} = 0;
+    }
     # retrieve individual items
-    $query = qq|SELECT (SELECT c.accno FROM chart c
-                       WHERE p.inventory_accno_id = c.id)
-                       AS inventory_accno,
-                      (SELECT c.accno FROM chart c
-                      WHERE p.income_accno_id = c.id)
-                      AS income_accno,
-                      (SELECT c.accno FROM chart c
-                      WHERE p.expense_accno_id = c.id)
-                      AS expense_accno,
-                i.description, i.qty, i.fxsellprice AS sellprice,
+    $query = qq|SELECT  
+                c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from as inventory_valid,
+               c2.accno AS income_accno, c2.new_chart_id AS income_new_chart, date($transdate)  - c2.valid_from as income_valid,
+               c3.accno AS expense_accno, c3.new_chart_id AS expense_new_chart, date($transdate) - c3.valid_from as expense_valid,
+                i.description, i.longdescription, i.qty, i.fxsellprice AS sellprice,
                i.discount, i.parts_id AS id, i.unit, i.deliverydate,
                i.project_id, pr.projectnumber, i.serialnumber,
-               p.partnumber, p.assembly, p.bin, p.notes AS partnotes, i.id AS invoice_pos,
+               p.partnumber, p.assembly, p.bin, p.notes AS partnotes, p.inventory_accno_id AS part_inventory_accno_id, i.id AS invoice_pos,
                pg.partsgroup, i.pricegroup_id, (SELECT pricegroup FROM pricegroup WHERE id=i.pricegroup_id) as pricegroup,
-               i.ordnumber, i.transdate, i.cusordnumber
+               i.ordnumber, i.transdate, i.cusordnumber, p.alu, p.formel, i.subtotal
                FROM invoice i
                JOIN parts p ON (i.parts_id = p.id)
                LEFT JOIN project pr ON (i.project_id = pr.id)
                LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
-               WHERE i.trans_id = $form->{id}
+               LEFT JOIN chart c1 ON ((select inventory_accno_id from buchungsgruppen where id=p.buchungsgruppen_id) = c1.id)
+               LEFT JOIN chart c2 ON ((select income_accno_id_$form->{taxzone_id} from buchungsgruppen where id=p.buchungsgruppen_id) = c2.id)
+               LEFT JOIN chart c3 ON ((select expense_accno_id_$form->{taxzone_id} from buchungsgruppen where id=p.buchungsgruppen_id) = c3.id)
+               WHERE i.trans_id = $form->{id}
                AND NOT i.assemblyitem = '1'
                ORDER BY i.id|;
     $sth = $dbh->prepare($query);
+
     $sth->execute || $form->dberror($query);
     while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+      if (!$ref->{"part_inventory_accno_id"}) {
+        map({ delete($ref->{$_}); } qw(inventory_accno inventory_new_chart inventory_valid));
+      }
+      delete($ref->{"part_inventory_accno_id"});
 
       #set expense_accno=inventory_accno if they are different => bilanz
+
+
+    while ($ref->{inventory_new_chart} && ($ref->{inventory_valid} >=0)) {
+      my $query = qq| SELECT accno AS inventory_accno, new_chart_id AS inventory_new_chart, date($transdate) - valid_from AS inventory_valid FROM chart WHERE id = $ref->{inventory_new_chart}|;
+      my $stw = $dbh->prepare($query);
+      $stw->execute || $form->dberror($query);
+      ($ref->{inventory_accno}, $ref->{inventory_new_chart}, $ref->{inventory_valid}) = $stw->fetchrow_array;
+      $stw->finish;
+    }
+
+    while ($ref->{income_new_chart} && ($ref->{income_valid} >=0)) {
+      my $query = qq| SELECT accno AS income_accno, new_chart_id AS income_new_chart, date($transdate) - valid_from AS income_valid FROM chart WHERE id = $ref->{income_new_chart}|;
+      my $stw = $dbh->prepare($query);
+      $stw->execute || $form->dberror($query);
+      ($ref->{income_accno}, $ref->{income_new_chart}, $ref->{income_valid}) = $stw->fetchrow_array;
+      $stw->finish;
+    }
+
+    while ($ref->{expense_new_chart} && ($ref->{expense_valid} >=0)) {
+      my $query = qq| SELECT accno AS expense_accno, new_chart_id AS expense_new_chart, date($transdate) - valid_from AS expense_valid FROM chart WHERE id = $ref->{expense_new_chart}|;
+      my $stw = $dbh->prepare($query);
+      $stw->execute || $form->dberror($query);
+      ($ref->{expense_accno}, $ref->{expense_new_chart}, $ref->{expense_valid}) = $stw->fetchrow_array;
+      $stw->finish;
+    }
+
       $vendor_accno =
         ($ref->{expense_accno} != $ref->{inventory_accno})
         ? $ref->{inventory_accno}
@@ -1246,20 +1605,26 @@ sub retrieve_invoice {
       # get tax rates and description
       $accno_id =
         ($form->{vc} eq "customer") ? $ref->{income_accno} : $vendor_accno;
-      $query = qq|SELECT c.accno, c.description, t.rate, t.taxnumber
-                FROM chart c, tax t
-                WHERE c.id=t.chart_id AND t.taxkey in (SELECT taxkey_id from chart where accno = '$accno_id')
+      $query = qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber
+                FROM tax t LEFT join chart c ON (c.id=t.chart_id)
+                WHERE t.taxkey in (SELECT taxkey_id from chart where accno = '$accno_id')
                 ORDER BY accno|;
       $stw = $dbh->prepare($query);
       $stw->execute || $form->dberror($query);
       $ref->{taxaccounts} = "";
+      my $i=0;
       while ($ptr = $stw->fetchrow_hashref(NAME_lc)) {
 
         #    if ($customertax{$ref->{accno}}) {
+        if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
+          $i++;
+          $ptr->{accno} = $i;
+        }
         $ref->{taxaccounts} .= "$ptr->{accno} ";
+
         if (!($form->{taxaccounts} =~ /$ptr->{accno}/)) {
           $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
-          $form->{"$ptr->{accno}_description"} = $ptr->{description};
+          $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
           $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
           $form->{taxaccounts} .= "$ptr->{accno} ";
         }
@@ -1277,6 +1642,9 @@ sub retrieve_invoice {
           "<option value=\"$licenseid\">$licensenumber</option>";
         $stg->finish();
       }
+      if ($form->{type} eq "credit_note") {
+        $ref->{qty} *= -1;
+      }
 
       chop $ref->{taxaccounts};
       push @{ $form->{invoice_details} }, $ref;
@@ -1317,10 +1685,10 @@ sub get_customer {
 
   # get customer
   my $query = qq|SELECT c.name AS customer, c.discount, c.creditlimit, c.terms,
-                 c.email, c.cc, c.bcc, c.language,
+                 c.email, c.cc, c.bcc, c.language_id, c.payment_id AS customer_payment_id,
                 c.street, c.zipcode, c.city, c.country,
                 $duedate + c.terms AS duedate, c.notes AS intnotes,
-                b.discount AS tradediscount, b.description AS business, c.klass as customer_klass
+                b.discount AS tradediscount, b.description AS business, c.klass as customer_klass, c.taxzone_id
                  FROM customer c
                 LEFT JOIN business b ON (b.id = c.business_id)
                 WHERE c.id = $form->{customer_id}|;
@@ -1332,6 +1700,45 @@ sub get_customer {
   map { $form->{$_} = $ref->{$_} } keys %$ref;
   $sth->finish;
 
+  my $query = qq|SELECT sum(a.amount-a.paid) AS dunning_amount FROM ar a WHERE a.paid < a.amount AND a.customer_id=$form->{customer_id} AND a.dunning_id IS NOT NULL|;
+  my $sth = $dbh->prepare($query);
+
+  $sth->execute || $form->dberror($query);
+  
+  $ref = $sth->fetchrow_hashref(NAME_lc);
+
+  map { $form->{$_} = $ref->{$_} } keys %$ref;
+  $sth->finish;
+
+  #print(STDERR "DUNNING AMOUTN $form->{dunning_amount}\n");
+
+  my $query = qq|SELECT dnn.dunning_description AS max_dunning_level FROM dunning_config dnn WHERE id in (select dunning_id from ar WHERE paid < amount AND customer_id=$form->{customer_id} AND dunning_id IS NOT NULL) ORDER BY dunning_level DESC LIMIT 1|;
+  my $sth = $dbh->prepare($query);
+
+  $sth->execute || $form->dberror($query);
+
+  $ref = $sth->fetchrow_hashref(NAME_lc);
+
+  map { $form->{$_} = $ref->{$_} } keys %$ref;
+  $sth->finish;
+  #print(STDERR "LEVEL $form->{max_dunning_level}\n");
+
+
+  #check whether payment_terms are better than old payment_terms
+  if (($form->{payment_id} ne "") && ($form->{customer_payment_id} ne "")) {
+    my $query = qq|select (select ranking from payment_terms WHERE id = $form->{payment_id}), (select ranking from payment_terms WHERE id = $form->{customer_payment_id})|;
+    my $stw = $dbh->prepare($query);
+    $stw->execute || $form->dberror($query);
+    ($old_ranking, $new_ranking) = $stw->fetchrow_array;
+    $stw->finish;
+    if ($new_ranking > $old_ranking) {
+      $form->{payment_id} =$form->{customer_payment_id};
+    }
+  }
+  if ($form->{payment_id} eq "") {
+    $form->{payment_id} =$form->{customer_payment_id};
+  }
+
   $form->{creditremaining} = $form->{creditlimit};
   $query = qq|SELECT SUM(a.amount - a.paid)
              FROM ar a
@@ -1361,10 +1768,10 @@ sub get_customer {
   $sth->finish;
 
   $form->get_contacts($dbh, $form->{customer_id});
-  ($null, $form->{cp_id}) = split /--/, $form->{contact};
+  $form->{cp_id} *= 1;
 
   # get contact if selected
-  if ($form->{contact} ne "--" && $form->{contact} ne "") {
+  if ($form->{cp_id}) {
     $form->get_contact($dbh, $form->{cp_id});
   }
 
@@ -1374,11 +1781,12 @@ sub get_customer {
       qw(shiptoname shiptodepartment_1 shiptodepartment_2 shiptostreet shiptozipcode shiptocity shiptocountry shiptocontact shiptophone shiptofax shiptoemail);
 
     $query = qq|SELECT s.* FROM shipto s
-                WHERE s.trans_id = $form->{customer_id}|;
+                WHERE s.trans_id = $form->{customer_id} AND s.module = 'CT'|;
     $sth = $dbh->prepare($query);
     $sth->execute || $form->dberror($query);
 
     $ref = $sth->fetchrow_hashref(NAME_lc);
+    undef($ref->{id});
     map { $form->{$_} = $ref->{$_} } keys %$ref;
     $sth->finish;
   }
@@ -1397,6 +1805,19 @@ sub get_customer {
   }
   $sth->finish;
 
+  # get shipping addresses
+  $query = qq|SELECT s.id,s.shiptoname
+              FROM shipto s
+             WHERE s.trans_id = $form->{customer_id}|;
+  $sth = $dbh->prepare($query);
+  $sth->execute || $form->dberror($query);
+
+  my $customertax = ();
+  while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+    push(@{ $form->{SHIPTO} }, $ref);
+  }
+  $sth->finish;
+
   # setup last accounts used for this customer
   if (!$form->{id} && $form->{type} !~ /_(order|quotation)/) {
     $query = qq|SELECT c.accno, c.description, c.link, c.category
@@ -1459,28 +1880,89 @@ sub retrieve_item {
     $where .= " ORDER BY p.partnumber";
   }
 
+  my $transdate = "";
+  if ($form->{type} eq "invoice") {
+    $transdate = "'$form->{invdate}'";
+  } elsif ($form->{type} eq "sales_order") {
+    $transdate = "'$form->{transdate}'";
+  } elsif ($form->{type} eq "sales_quotation") {
+    $transdate = "'$form->{transdate}'";
+  }
+
+  if ($transdate eq "") {
+    $transdate = "current_date";
+  }
+
   # connect to database
   my $dbh = $form->dbconnect($myconfig);
 
   my $query = qq|SELECT p.id, p.partnumber, p.description, p.sellprice,
-                        p.listprice,
-                        c1.accno AS inventory_accno,
-                       c2.accno AS income_accno,
-                       c3.accno AS expense_accno,
-                p.unit, p.assembly, p.bin, p.onhand, p.notes AS partnotes,
-                pg.partsgroup
+                        p.listprice, p.inventory_accno_id,
+                        c1.accno AS inventory_accno, c1.new_chart_id AS inventory_new_chart, date($transdate) - c1.valid_from as inventory_valid,
+                       c2.accno AS income_accno, c2.new_chart_id AS income_new_chart, date($transdate)  - c2.valid_from as income_valid,
+                       c3.accno AS expense_accno, c3.new_chart_id AS expense_new_chart, date($transdate) - c3.valid_from as expense_valid,
+                p.unit, p.assembly, p.bin, p.onhand, p.notes AS partnotes, p.notes AS longdescription, p.not_discountable,
+                pg.partsgroup, p.formel, p.alu, p.payment_id AS part_payment_id, adr.adr_description
                  FROM parts p
-                LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id)
-                LEFT JOIN chart c2 ON (p.income_accno_id = c2.id)
-                LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id)
+                LEFT JOIN chart c1 ON ((select inventory_accno_id from buchungsgruppen where id=p.buchungsgruppen_id) = c1.id)
+                LEFT JOIN chart c2 ON ((select income_accno_id_$form->{taxzone_id} from buchungsgruppen where id=p.buchungsgruppen_id) = c2.id)
+                LEFT JOIN chart c3 ON ((select expense_accno_id_$form->{taxzone_id} from buchungsgruppen where id=p.buchungsgruppen_id) = c3.id)
                 LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
+                 LEFT JOIN adr adr ON (adr.id = p.adr_id)
                 WHERE $where|;
   my $sth = $dbh->prepare($query);
   $sth->execute || $form->dberror($query);
 
   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
 
+    # In der Buchungsgruppe ist immer ein Bestandskonto verknuepft, auch wenn
+    # es sich um eine Dienstleistung handelt. Bei Dienstleistungen muss das
+    # Buchungskonto also aus dem Ergebnis rausgenommen werden.
+    if (!$ref->{inventory_accno_id}) {
+      map({ delete($ref->{"inventory_${_}"}); } qw(accno new_chart valid));
+    }
+    delete($ref->{inventory_accno_id});
+
     #set expense_accno=inventory_accno if they are different => bilanz
+
+
+    while ($ref->{inventory_new_chart} && ($ref->{inventory_valid} >=0)) {
+      my $query = qq| SELECT accno AS inventory_accno, new_chart_id AS inventory_new_chart, date($transdate) - valid_from AS inventory_valid FROM chart WHERE id = $ref->{inventory_new_chart}|;
+      my $stw = $dbh->prepare($query);
+      $stw->execute || $form->dberror($query);
+      ($ref->{inventory_accno}, $ref->{inventory_new_chart}, $ref->{inventory_valid}) = $stw->fetchrow_array;
+      $stw->finish;
+    }
+
+    while ($ref->{income_new_chart} && ($ref->{income_valid} >=0)) {
+      my $query = qq| SELECT accno AS income_accno, new_chart_id AS income_new_chart, date($transdate) - valid_from AS income_valid FROM chart WHERE id = $ref->{income_new_chart}|;
+      my $stw = $dbh->prepare($query);
+      $stw->execute || $form->dberror($query);
+      ($ref->{income_accno}, $ref->{income_new_chart}, $ref->{income_valid}) = $stw->fetchrow_array;
+      $stw->finish;
+    }
+
+    while ($ref->{expense_new_chart} && ($ref->{expense_valid} >=0)) {
+      my $query = qq| SELECT accno AS expense_accno, new_chart_id AS expense_new_chart, date($transdate) - valid_from AS expense_valid FROM chart WHERE id = $ref->{expense_new_chart}|;
+      my $stw = $dbh->prepare($query);
+      $stw->execute || $form->dberror($query);
+      ($ref->{expense_accno}, $ref->{expense_new_chart}, $ref->{expense_valid}) = $stw->fetchrow_array;
+      $stw->finish;
+    }
+
+    #check whether payment_terms are better than old payment_terms
+    if (($form->{payment_id} ne "") && ($ref->{part_payment_id} ne "")) {
+      my $query = qq|select (select ranking from payment_terms WHERE id = $form->{payment_id}), (select ranking from payment_terms WHERE id = $ref->{part_payment_id})|;
+      my $stw = $dbh->prepare($query);
+      $stw->execute || $form->dberror($query);
+      ($old_ranking, $new_ranking) = $stw->fetchrow_array;
+      $stw->finish;
+      if ($new_ranking <= $old_ranking) {
+        $ref->{part_payment_id} = "";
+      }
+    }
+
+
     $vendor_accno =
       ($ref->{expense_accno} != $ref->{inventory_accno})
       ? $ref->{inventory_accno}
@@ -1489,21 +1971,27 @@ sub retrieve_item {
     # get tax rates and description
     $accno_id =
       ($form->{vc} eq "customer") ? $ref->{income_accno} : $vendor_accno;
-    $query = qq|SELECT c.accno, c.description, t.rate, t.taxnumber
-             FROM chart c, tax t
-             WHERE c.id=t.chart_id AND t.taxkey in (SELECT c2.taxkey_id from chart c2 where c2.accno = '$accno_id')
+    $query = qq|SELECT c.accno, t.taxdescription, t.rate, t.taxnumber
+             FROM tax t LEFT JOIN chart c on (c.id=t.chart_id)
+             WHERE t.taxkey in (SELECT c2.taxkey_id from chart c2 where c2.accno = '$accno_id')
              ORDER BY c.accno|;
     $stw = $dbh->prepare($query);
     $stw->execute || $form->dberror($query);
 
     $ref->{taxaccounts} = "";
+    my $i = 0;
     while ($ptr = $stw->fetchrow_hashref(NAME_lc)) {
 
       #    if ($customertax{$ref->{accno}}) {
+      if (($ptr->{accno} eq "") && ($ptr->{rate} == 0)) {
+        $i++;
+        $ptr->{accno} = $i;
+      }
       $ref->{taxaccounts} .= "$ptr->{accno} ";
+
       if (!($form->{taxaccounts} =~ /$ptr->{accno}/)) {
         $form->{"$ptr->{accno}_rate"}        = $ptr->{rate};
-        $form->{"$ptr->{accno}_description"} = $ptr->{description};
+        $form->{"$ptr->{accno}_description"} = $ptr->{taxdescription};
         $form->{"$ptr->{accno}_taxnumber"}   = $ptr->{taxnumber};
         $form->{taxaccounts} .= "$ptr->{accno} ";
       }
@@ -1512,6 +2000,32 @@ sub retrieve_item {
 
     $stw->finish;
     chop $ref->{taxaccounts};
+    if ($form->{language_id}) {
+      $query = qq|SELECT tr.translation, tr.longdescription
+                FROM translation tr
+                WHERE tr.language_id=$form->{language_id} AND tr.parts_id=$ref->{id}|;
+      $stw = $dbh->prepare($query);
+      $stw->execute || $form->dberror($query);
+      my ($translation, $longdescription) = $stw->fetchrow_array();
+      if ($translation ne "") {
+        $ref->{description} = $translation;
+        $ref->{longdescription} = $longdescription;
+
+      } else {
+        $query = qq|SELECT tr.translation, tr.longdescription
+                FROM translation tr
+                WHERE tr.language_id in (select id from language where article_code=(select article_code from language where id = $form->{language_id})) AND tr.parts_id=$ref->{id} LIMIT 1|;
+        $stg = $dbh->prepare($query);
+        $stg->execute || $form->dberror($query);
+        my ($translation) = $stg->fetchrow_array();
+        if ($translation ne "") {
+          $ref->{description} = $translation;
+          $ref->{longdescription} = $longdescription;
+        }
+        $stg->finish;
+      }
+      $stw->finish;
+    }
 
     push @{ $form->{item_list} }, $ref;
 
@@ -1550,7 +2064,9 @@ sub get_pricegroups_for_parts {
 
   my $i  = 1;
   my $id = 0;
-
+  my $dimension_units = AM->retrieve_units($myconfig, $form, "dimension");
+  my $service_units = AM->retrieve_units($myconfig, $form, "service");
+  my $all_units = AM->retrieve_units($myconfig, $form);
   while (($form->{"id_$i"}) or ($form->{"new_id_$i"})) {
 
     $id = $form->{"id_$i"};
@@ -1564,20 +2080,52 @@ sub get_pricegroups_for_parts {
       $form->{"sellprice_drag_$i"};
 
     $pricegroup_old = $form->{"pricegroup_old_$i"};
-
+    $form->{"new_pricegroup_$i"} = $selectedpricegroup_id;
+    $form->{"old_pricegroup_$i"} = $pricegroup_old;
     $price_new = $form->{"price_new_$i"};
 
     $price_old = $form->{"price_old_$i"};
-
     $query =
       qq|SELECT pricegroup_id, (SELECT p.sellprice from parts p where p.id = $id) as default_sellprice,(SELECT pg.pricegroup FROM pricegroup pg WHERE id=pricegroup_id) AS pricegroup, price, '' AS selected FROM prices WHERE parts_id = $id UNION SELECT 0 as pricegroup_id,(SELECT sellprice FROM parts WHERE id=$id) as default_sellprice,'' as pricegroup, (SELECT DISTINCT sellprice from parts where id=$id) as price, 'selected' AS selected from prices ORDER BY pricegroup|;
 
     $pkq = $dbh->prepare($query);
     $pkq->execute || $form->dberror($query);
+    if (!$form->{"unit_old_$i"}) {
+      # Neue Ware aus der Datenbank. In diesem Fall ist unit_$i die
+      # Einheit, wie sie in den Stammdaten hinterlegt wurde.
+      # Es sollte also angenommen werden, dass diese ausgewaehlt war.
+      $form->{"unit_old_$i"} = $form->{"unit_$i"};
+    }
+    # Die zuletzt ausgewaehlte mit der aktuell ausgewaehlten Einheit
+    # vergleichen und bei Unterschied den Preis entsprechend umrechnen.
+    $form->{"selected_unit_$i"} = $form->{"unit_$i"} unless ($form->{"selected_unit_$i"});
+
+    my $check_units = $form->{"inventory_accno_$i"} ? $dimension_units : $service_units;
+    if (!$check_units->{$form->{"selected_unit_$i"}} ||
+        ($check_units->{$form->{"selected_unit_$i"}}->{"base_unit"} ne
+         $all_units->{$form->{"unit_old_$i"}}->{"base_unit"})) {
+      # Die ausgewaehlte Einheit ist fuer diesen Artikel nicht gueltig
+      # (z.B. Dimensionseinheit war ausgewaehlt, es handelt sich aber
+      # um eine Dienstleistung). Dann keinerlei Umrechnung vornehmen.
+      $form->{"unit_old_$i"} = $form->{"selected_unit_$i"} = $form->{"unit_$i"};
+    }
+    my $basefactor = 1;
+    
+    if ($form->{"unit_old_$i"} ne $form->{"selected_unit_$i"}) {
+      if (defined($all_units->{$form->{"unit_old_$i"}}->{"factor"}) &&
+          $all_units->{$form->{"unit_old_$i"}}->{"factor"}) {
+        $basefactor = $all_units->{$form->{"selected_unit_$i"}}->{"factor"} /
+          $all_units->{$form->{"unit_old_$i"}}->{"factor"};
+      }
+    }
+    if (!$form->{"basefactor_$i"}) {
+      $form->{"basefactor_$i"} = 1;
+    }
     while ($pkr = $pkq->fetchrow_hashref(NAME_lc)) {
 
       #       push @{ $form->{PRICES}{$id} }, $pkr;
-      push @{ $form->{PRICES}{$i} }, $pkr;
+      #push @{ $form->{PRICES}{$i} }, $pkr;
       $pkr->{id}       = $id;
       $pkr->{selected} = '';
 
@@ -1586,13 +2134,17 @@ sub get_pricegroups_for_parts {
 
         $pkr->{price} /= $form->{exchangerate};
       }
+
+      $pkr->{price} *= $form->{"basefactor_$i"};
+      
+      $pkr->{price} *= $basefactor;
       $pkr->{price} = $form->format_amount($myconfig, $pkr->{price}, 5);
 
       if ($selectedpricegroup_id eq undef) {
         if ($pkr->{pricegroup_id} eq $form->{customer_klass}) {
 
           $pkr->{selected}  = ' selected';
-          $last->{selected} = '';
 
           # no customer pricesgroup set
           if ($pkr->{price} == $pkr->{default_sellprice}) {
@@ -1612,26 +2164,21 @@ sub get_pricegroups_for_parts {
           }
         }
       }
+
       if ($selectedpricegroup_id or $selectedpricegroup_id == 0) {
         if ($selectedpricegroup_id ne $pricegroup_old) {
           if ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
-            if ($price_new != $form->{"sellprice_$i"}) {
-            } else {
-              $pkr->{selected}  = ' selected';
-              $last->{selected} = '';
-            }
+            $pkr->{selected}  = ' selected';
           }
         } else {
           if (($price_new != $form->{"sellprice_$i"}) and ($price_new ne 0)) {
             if ($pkr->{pricegroup_id} == 0) {
               $pkr->{price}     = $form->{"sellprice_$i"};
               $pkr->{selected}  = ' selected';
-              $last->{selected} = '';
             }
           } else {
             if ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
               $pkr->{selected}  = ' selected';
-              $last->{selected} = '';
               if (    ($pkr->{pricegroup_id} == 0)
                   and ($pkr->{price} == $form->{"sellprice_$i"})) {
 
@@ -1643,7 +2190,11 @@ sub get_pricegroups_for_parts {
           }
         }
       }
+      push @{ $form->{PRICES}{$i} }, $pkr;
+
     }
+    $form->{"basefactor_$i"} *= $basefactor;
+
     $i++;
 
     $pkq->finish;