X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FDB%2FOrder.pm;h=6baa0e20dc7905f0fa70e493dbb86115a23758ee;hb=862dfb20115843050efddb16828fd455fe3c9456;hp=7d5e2fe4aaacf7f350d77f17791507717d7d56a8;hpb=5af4094befe484e6fbe2e2787cf53e85844629fc;p=kivitendo-erp.git diff --git a/SL/DB/Order.pm b/SL/DB/Order.pm index 7d5e2fe4a..6baa0e20d 100644 --- a/SL/DB/Order.pm +++ b/SL/DB/Order.pm @@ -189,9 +189,99 @@ sub convert_to_delivery_order { return $delivery_order; } +sub _clone_orderitem_cvar { + my ($cvar) = @_; + + my $cloned = $_->clone_and_reset; + $cloned->sub_module('orderitems'); + + return $cloned; +} + +sub new_from { + my ($class, $source, %params) = @_; + + croak("Unsupported source object type '" . ref($source) . "'") unless ref($source) eq 'SL::DB::Order'; + croak("A destination type must be given parameter") unless $params{destination_type}; + + my $destination_type = delete $params{destination_type}; + my $src_dst_allowed = ('sales_quotation' eq $source->type && 'sales_order' eq $destination_type) + || ('request_quotation' eq $source->type && 'purchase_order' eq $destination_type) + || ('sales_quotation' eq $source->type && 'sales_quotation' eq $destination_type) + || ('sales_order' eq $source->type && 'sales_order' eq $destination_type) + || ('request_quotation' eq $source->type && 'request_quotation' eq $destination_type) + || ('purchase_order' eq $source->type && 'purchase_order' eq $destination_type); + croak("Cannot convert from '" . $source->type . "' to '" . $destination_type . "'") unless $src_dst_allowed; + + 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 %args = ( map({ ( $_ => $source->$_ ) } qw(amount cp_id currency_id cusordnumber customer_id delivery_customer_id delivery_term_id delivery_vendor_id + department_id employee_id globalproject_id intnotes marge_percent marge_total language_id netamount notes + ordnumber payment_id quonumber reqdate salesman_id shippingpoint shipvia taxincluded taxzone_id + transaction_description vendor_id + )), + quotation => !!($destination_type =~ m{quotation$}), + closed => 0, + delivered => 0, + transdate => DateTime->today_local, + ); + + # Custom shipto addresses (the ones specific to the sales/purchase + # record and not to the customer/vendor) are only linked from + # shipto → order. Meaning order.shipto_id + # will not be filled in that case. + if (!$source->shipto_id && $source->id) { + $args{custom_shipto} = $source->custom_shipto->clone($class) if $source->can('custom_shipto') && $source->custom_shipto; + + } else { + $args{shipto_id} = $source->shipto_id; + } + + my $order = $class->new(%args); + $order->assign_attributes(%{ $params{attributes} }) if $params{attributes}; + my $items = delete($params{items}) || $source->items_sorted; + my %item_parents; + + my @items = map { + 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}; + + my $current_oe_item = SL::DB::OrderItem->new(map({ ( $_ => $source_item->$_ ) } + qw(active_discount_source active_price_source base_qty cusordnumber + description discount lastcost longdescription + marge_percent marge_price_factor marge_total + ordnumber parts_id price_factor price_factor_id pricegroup_id + project_id qty reqdate sellprice serialnumber ship subtotal transdate unit + )), + custom_variables => \@custom_variables, + ); + $current_oe_item->{"converted_from_orderitems_id"} = $_->{id} if ref($item_parent) eq 'SL::DB::Order'; + $current_oe_item; + } @{ $items }; + + @items = grep { $params{item_filter}->($_) } @items if $params{item_filter}; + @items = grep { $_->qty * 1 } @items if $params{skip_items_zero_qty}; + @items = grep { $_->qty >=0 } @items if $params{skip_items_negative_qty}; + + $order->items(\@items); + + return $order; +} + sub number { my $self = shift; + return if !$self->type; + my %number_method = ( sales_order => 'ordnumber', sales_quotation => 'quonumber', @@ -283,6 +373,62 @@ nothing is created or changed in the database. At the moment only sales quotations and sales orders can be converted. +=head2 C + +Creates a new C instance and copies as much +information from C<$source> as possible. At the moment only records with the +same destination type as the source type and sales orders from +sales quotations and purchase orders from requests for quotations can be +created. + +The C field will be set to the current date. + +The conversion copies the order items as well. + +Returns the new order instance. The object returned is not +saved. + +C<%params> can include the following options +(C is mandatory): + +=over 4 + +=item C + +(mandatory) +The type of the newly created object. Can be C, +C, C or C for now. + +=item C + +An optional array reference of RDBO instances for the items to use. If +missing then the method C 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 + +If trueish then items with a negative quantity are skipped. Items with +a quantity of 0 are not affected by this option. + +=item C + +If trueish then items with a quantity of 0 are skipped. + +=item C + +An optional code reference that is called for each item with the item +as its sole parameter. Items for which the code reference returns a +falsish value will be skipped. + +=item C + +An optional hash reference. If it exists then it is passed to C +allowing the caller to set certain attributes for the new delivery +order. + +=back + =head2 C Creates and saves a new sales process. Can only be called for sales