Merge branch 'b-3.6.1' into mebil
[kivitendo-erp.git] / SL / Controller / CsvImport / DeliveryOrder.pm
index 62ecb11..2e5a9e9 100644 (file)
@@ -9,6 +9,7 @@ use DateTime;
 
 use SL::Controller::CsvImport::Helper::Consistency;
 use SL::DB::DeliveryOrder;
+use SL::DB::DeliveryOrder::TypeData qw(:types);
 use SL::DB::DeliveryOrderItem;
 use SL::DB::DeliveryOrderItemsStock;
 use SL::DB::Part;
@@ -21,6 +22,7 @@ use SL::DB::Unit;
 use SL::DB::Inventory;
 use SL::DB::TransferType;
 use SL::DBUtils;
+use SL::Helper::ShippedQty;
 use SL::PriceSource;
 use SL::TransNumber;
 use SL::Util qw(trim);
@@ -214,10 +216,10 @@ sub setup_displayable_columns {
                                  { name => 'globalprojectnumber',     description => $::locale->text('Document Project (number)')             },
                                  { name => 'globalproject_id',        description => $::locale->text('Document Project (database ID)')        },
                                  { name => 'intnotes',                description => $::locale->text('Internal Notes')                        },
-                                 { name => 'is_sales',                description => $::locale->text('Is sales')                              },
                                  { name => 'language',                description => $::locale->text('Language (name)')                       },
                                  { name => 'language_id',             description => $::locale->text('Language (database ID)')                },
                                  { name => 'notes',                   description => $::locale->text('Notes')                                 },
+                                 { name => 'order_type',              description => $::locale->text('Delivery Order Type')                   },
                                  { name => 'ordnumber',               description => $::locale->text('Order Number')                          },
                                  { name => 'payment',                 description => $::locale->text('Payment terms (name)')                  },
                                  { name => 'payment_id',              description => $::locale->text('Payment terms (database ID)')           },
@@ -552,7 +554,7 @@ sub handle_order {
     push @{ $entry->{errors} }, $::locale->text('Error: Customer/vendor missing');
   }
 
-  $self->handle_is_sales($entry);
+  $self->handle_type($entry);
   $self->check_contact($entry);
   $self->check_language($entry);
   $self->check_payment($entry);
@@ -684,11 +686,19 @@ sub handle_stock {
   }
 }
 
-sub handle_is_sales {
+sub handle_type {
   my ($self, $entry) = @_;
 
-  if (!exists $entry->{raw_data}->{is_sales}) {
-    $entry->{object}->is_sales(!!$entry->{object}->customer_id);
+  if (!exists $entry->{raw_data}->{order_type}) {
+    # if no type is present - set to sales delivery order or purchase delivery
+    # order depending on is_sales or customer/vendor
+
+    $entry->{object}->order_type(
+      $entry->{object}->customer_id  ? SALES_DELIVERY_ORDER_TYPE :
+      $entry->{object}->vendor_id    ? PURCHASE_DELIVERY_ORDER_TYPE :
+      $entry->{raw_data}->{is_sales} ? SALES_DELIVERY_ORDER_TYPE :
+                                       PURCHASE_DELIVERY_ORDER_TYPE
+    );
   }
 }
 
@@ -710,6 +720,10 @@ sub handle_order_sources {
     push @{ $entry->{errors} }, $::locale->text('Error: More than one source order found');
   }
 
+  foreach my $order (@$orders) {
+    $self->{remaining_source_qtys_by_item_id} = { map { $_->id => $_->qty } @{ $order->items } };
+  }
+
   $record->{source_orders} = $orders;
 }
 
@@ -721,9 +735,38 @@ sub handle_item_source {
 
   return if !@{ $record->{source_orders} };
 
+  # Todo: units?
+
   foreach my $order (@{ $record->{source_orders} }) {
-    $item->{source_item} = first { $item->parts_id == $_->parts_id && $item->qty == $_->qty} @{ $order->items_sorted };
-    last if $item->{source_item};
+    # First: Excact matches and source order position is still complete.
+    $item->{source_item} = first {
+         $item->parts_id                                     == $_->parts_id
+      && $item->qty                                          == $_->qty
+      && $self->{remaining_source_qtys_by_item_id}->{$_->id} == $_->qty
+    } @{ $order->items_sorted };
+    if ($item->{source_item}) {
+      $self->{remaining_source_qtys_by_item_id}->{$item->{source_item}->id} -= $item->qty;
+      last;
+    }
+
+    # Second: Smallest remaining order qty greater or equal delivery order qty.
+    $item->{source_item} = first {
+         $item->parts_id                                     == $_->parts_id
+      && $self->{remaining_source_qtys_by_item_id}->{$_->id} >= $item->qty
+    } sort { $self->{remaining_source_qtys_by_item_id}->{$a->id} <=> $self->{remaining_source_qtys_by_item_id}->{$b->id} } @{ $order->items_sorted };
+    if ($item->{source_item}) {
+      $self->{remaining_source_qtys_by_item_id}->{$item->{source_item}->id} -= $item->qty;
+      last;
+    }
+
+    # Last: Overdelivery?
+    # $item->{source_item} = first {
+    #      $item->parts_id == $_->parts_id
+    # } @{ $order->items_sorted };
+    # if ($item->{source_item}) {
+    #   $self->{remaining_source_qtys_by_item_id}->{$item->{source_item}->id} -= $item->qty;
+    #   last;
+    # }
   }
 }
 
@@ -1112,18 +1155,8 @@ sub save_additions {
 
   # delivery order for all positions created?
   if (scalar(@$orders)) {
-    foreach my $order (@{ $orders }) {
-      my $all_deliverd;
-      foreach my $orderitem (@{ $order->items }) {
-        my $delivered_qty = 0;
-        foreach my $do_item (@{$orderitem->linked_records(to => 'DeliveryOrderItem')}) {
-          $delivered_qty += $do_item->unit_obj->convert_to($do_item->qty, $orderitem->unit_obj);
-        }
-        $all_deliverd = $orderitem->qty <= $delivered_qty;
-        last if !$all_deliverd;
-      }
-      $order->update_attributes(delivered => !!$all_deliverd);
-    }
+    SL::Helper::ShippedQty->new->calculate($orders)->write_to_objects;
+    $_->update_attributes(delivered => $_->delivered) for @{ $orders };
   }
 
   # inventory (or use WH->transfer?)