SL::DB::Helper::LinkedRecords: rekursive Suche in linked_records
[kivitendo-erp.git] / SL / DB / DeliveryOrder.pm
index cc4d930..75eab64 100644 (file)
@@ -4,6 +4,8 @@ use strict;
 
 use Carp;
 
 
 use Carp;
 
+use Rose::DB::Object::Helpers ();
+
 use SL::DB::MetaSetup::DeliveryOrder;
 use SL::DB::Manager::DeliveryOrder;
 use SL::DB::Helper::FlattenToForm;
 use SL::DB::MetaSetup::DeliveryOrder;
 use SL::DB::Manager::DeliveryOrder;
 use SL::DB::Helper::FlattenToForm;
@@ -81,11 +83,27 @@ sub date {
   goto &transdate;
 }
 
   goto &transdate;
 }
 
+sub _clone_orderitem_cvar {
+  my ($cvar) = @_;
+
+  my $cloned = Rose::DB::Object::Helpers::clone_and_reset($_);
+  $cloned->sub_module('delivery_order_items');
+
+  return $cloned;
+}
+
 sub new_from {
   my ($class, $source, %params) = @_;
 
   croak("Unsupported source object type '" . ref($source) . "'") unless ref($source) eq 'SL::DB::Order';
 
 sub new_from {
   my ($class, $source, %params) = @_;
 
   croak("Unsupported source object type '" . ref($source) . "'") unless ref($source) eq 'SL::DB::Order';
 
+  my ($item_parent_id_column, $item_parent_column);
+
+  if (ref($source) eq 'SL::DB::Order') {
+    $item_parent_id_column = 'trans_id';
+    $item_parent_column    = 'order';
+  }
+
   my $terms = $source->can('payment_id') && $source->payment_id ? $source->payment_terms->terms_netto : 0;
 
   my %args = ( map({ ( $_ => $source->$_ ) } qw(cp_id currency_id customer_id cusordnumber department_id employee_id globalproject_id intnotes language_id notes
   my $terms = $source->can('payment_id') && $source->payment_id ? $source->payment_terms->terms_netto : 0;
 
   my %args = ( map({ ( $_ => $source->$_ ) } qw(cp_id currency_id customer_id cusordnumber department_id employee_id globalproject_id intnotes language_id notes
@@ -121,15 +139,29 @@ sub new_from {
     $args{shipto_id} = $source->shipto_id;
   }
 
     $args{shipto_id} = $source->shipto_id;
   }
 
-  my $delivery_order = $class->new(%args, %params);
+  my $delivery_order = $class->new(%args, %{ $params{attributes} || {} });
+  my $items          = delete($params{items}) || $source->items_sorted;
+  my %item_parents;
 
   my @items = map {
 
   my @items = map {
-    my $source_item = $_;
+    my $source_item      = $_;
+    my $source_item_id   = $_->$item_parent_id_column;
+    my @custom_variables = map { _clone_orderitem_cvar($_) } @{ $source_item->custom_variables };
+
+    $item_parents{$source_item_id} ||= $source_item->$item_parent_column;
+    my $item_parent                  = $item_parents{$source_item_id};
+
     SL::DB::DeliveryOrderItem->new(map({ ( $_ => $source_item->$_ ) }
     SL::DB::DeliveryOrderItem->new(map({ ( $_ => $source_item->$_ ) }
-                                   qw(base_qty cusordnumber description discount lastcost longdescription marge_price_factor ordnumber parts_id price_factor price_factor_id
-                                      project_id qty reqdate sellprice serialnumber transdate unit
-                                   )));
-  } @{ $source->items_sorted };
+                                         qw(base_qty cusordnumber description discount lastcost longdescription marge_price_factor parts_id price_factor price_factor_id
+                                            project_id qty reqdate sellprice serialnumber transdate unit
+                                         )),
+                                   custom_variables => \@custom_variables,
+                                   ordnumber        => ref($item_parent) eq 'SL::DB::Order' ? $item_parent->ordnumber : $source_item->ordnumber,
+                                 );
+
+  } @{ $items };
+
+  @items = grep { $_->qty * 1 } @items if $params{skip_items_zero_qty};
 
   $delivery_order->items(\@items);
 
 
   $delivery_order->items(\@items);
 
@@ -154,7 +186,7 @@ SL::DB::DeliveryOrder - Rose model for delivery orders (table
 
 =item C<date>
 
 
 =item C<date>
 
-An alias for L</transdate> for compatibility with other sales/purchase models.
+An alias for C<transdate> for compatibility with other sales/purchase models.
 
 =item C<displayable_state>
 
 
 =item C<displayable_state>
 
@@ -163,7 +195,7 @@ closed and delivered.
 
 =item C<items>
 
 
 =item C<items>
 
-An alias for L</deliver_orer_items> for compatibility with other
+An alias for C<deliver_orer_items> for compatibility with other
 sales/purchase models.
 
 =item C<items_sorted>
 sales/purchase models.
 
 =item C<items_sorted>
@@ -171,7 +203,7 @@ sales/purchase models.
 Returns the delivery order items sorted by their ID (same order they
 appear in the frontend delivery order masks).
 
 Returns the delivery order items sorted by their ID (same order they
 appear in the frontend delivery order masks).
 
-=item C<new_from $source>
+=item C<new_from $source, %params>
 
 Creates a new C<SL::DB::DeliveryOrder> instance and copies as much
 information from C<$source> as possible. At the moment only instances
 
 Creates a new C<SL::DB::DeliveryOrder> instance and copies as much
 information from C<$source> as possible. At the moment only instances
@@ -194,6 +226,29 @@ and returned.
 
 The objects returned are not saved.
 
 
 The objects returned are not saved.
 
+C<%params> can include the following options:
+
+=over 2
+
+=item C<items>
+
+An optional array reference of RDBO instances for the items to use. If
+missing then the method C<items_sorted> will be called on
+C<$source>. This option can be used to override the sorting, to
+exclude certain positions or to add additional ones.
+
+=item C<skip_items_zero_qty>
+
+If trueish then items with a quantity of 0 are skipped.
+
+=item C<attributes>
+
+An optional hash reference. If it exists then it is passed to C<new>
+allowing the caller to set certain attributes for the new delivery
+order.
+
+=back
+
 =item C<sales_order>
 
 TODO: Describe sales_order
 =item C<sales_order>
 
 TODO: Describe sales_order