sub _clone_orderitem_cvar {
my ($cvar) = @_;
- my $cloned = Rose::DB::Object::Helpers::clone_and_reset($_);
+ my $cloned = $_->clone_and_reset;
$cloned->sub_module('delivery_order_items');
return $cloned;
$item_parent_column = 'order';
}
- my %args = ( map({ ( $_ => $source->$_ ) } qw(cp_id currency_id customer_id cusordnumber department_id employee_id globalproject_id intnotes language_id notes
+ my %args = ( map({ ( $_ => $source->$_ ) } qw(cp_id currency_id customer_id cusordnumber delivery_term_id department_id employee_id globalproject_id intnotes language_id notes
ordnumber payment_id reqdate salesman_id shippingpoint shipvia taxincluded taxzone_id transaction_description vendor_id
)),
closed => 0,
# Custom shipto addresses (the ones specific to the sales/purchase
# record and not to the customer/vendor) are only linked from
- # shipto -> delivery_orders. Meaning delivery_orders.shipto_id
- # will not be filled in that case. Therefore we have to return the
- # new shipto object as a separate object so that the caller can
- # save it, too.
- my $custom_shipto;
+ # shipto → delivery_orders. Meaning delivery_orders.shipto_id
+ # will not be filled in that case.
if (!$source->shipto_id && $source->id) {
- my $old = $source->custom_shipto;
- if ($old) {
- $custom_shipto = SL::DB::Shipto->new(
- map { +($_ => $old->$_) }
- grep { !m{^ (?: itime | mtime | shipto_id | trans_id ) $}x }
- map { $_->name }
- @{ $old->meta->columns }
- );
- $custom_shipto->module('DO');
- }
+ $args{custom_shipto} = $source->custom_shipto->clone($class) if $source->can('custom_shipto') && $source->custom_shipto;
} else {
$args{shipto_id} = $source->shipto_id;
$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->$_ ) }
+ my $current_do_item = SL::DB::DeliveryOrderItem->new(map({ ( $_ => $source_item->$_ ) }
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 active_discount_source active_price_source
)),
custom_variables => \@custom_variables,
ordnumber => ref($item_parent) eq 'SL::DB::Order' ? $item_parent->ordnumber : $source_item->ordnumber,
);
-
+ $current_do_item->{"converted_from_orderitems_id"} = $_->{id} if ref($item_parent) eq 'SL::DB::Order';
+ $current_do_item;
} @{ $items };
@items = grep { $params{item_filter}->($_) } @items if $params{item_filter};
$delivery_order->items(\@items);
- return ($delivery_order, $custom_shipto);
+ return $delivery_order;
}
sub customervendor {
$_[0]->is_sales ? $_[0]->customer : $_[0]->vendor;
}
+sub convert_to_invoice {
+ my ($self, %params) = @_;
+
+ croak("Conversion to invoices is only supported for sales records") unless $self->customer_id;
+
+ my $invoice;
+ if (!$self->db->with_transaction(sub {
+ require SL::DB::Invoice;
+ $invoice = SL::DB::Invoice->new_from($self, %params)->post || die;
+ $self->link_to_record($invoice);
+ # TODO extend link_to_record for items, otherwise long-term no d.r.y.
+ foreach my $item (@{ $invoice->items }) {
+ foreach (qw(delivery_order_items)) { # expand if needed (orderitems)
+ if ($item->{"converted_from_${_}_id"}) {
+ die unless $item->{id};
+ RecordLinks->create_links('mode' => 'ids',
+ 'from_table' => $_,
+ 'from_ids' => $item->{"converted_from_${_}_id"},
+ 'to_table' => 'invoice',
+ 'to_id' => $item->{id},
+ ) || die;
+ delete $item->{"converted_from_${_}_id"};
+ }
+ }
+ }
+ $self->update_attributes(closed => 1);
+ 1;
+ })) {
+ return undef;
+ }
+
+ return $invoice;
+}
+
1;
__END__
The conversion copies order items into delivery order items. Dates are copied
as appropriate, e.g. the C<transdate> field will be set to the current date.
-Returns one or two objects depending on the context. In list context
-the new delivery order instance and a shipto instance will be
-returned. In scalar instance only the delivery order instance is
-returned.
-
-Custom shipto addresses (the ones specific to the sales/purchase
-record and not to the customer/vendor) are only linked from C<shipto>
-to C<delivery_orders>. Meaning C<delivery_orders.shipto_id> will not
-be filled in that case. That's why a separate shipto object is created
-and returned.
-
-The objects returned are not saved.
+Returns the new delivery order instance. The object returned is not
+saved.
C<%params> can include the following options:
Returns a string describing this record's type: either
C<sales_delivery_order> or C<purchase_delivery_order>.
+=item C<convert_to_invoice %params>
+
+Creates a new invoice with C<$self> as the basis by calling
+L<SL::DB::Invoice::new_from>. That invoice is posted, and C<$self> is
+linked to the new invoice via L<SL::DB::RecordLink>. C<$self>'s
+C<closed> attribute is set to C<true>, and C<$self> is saved.
+
+The arguments in C<%params> are passed to L<SL::DB::Invoice::new_from>.
+
+Returns the new invoice instance on success and C<undef> on
+failure. The whole process is run inside a transaction. On failure
+nothing is created or changed in the database.
+
+At the moment only sales delivery orders can be converted.
+
=back
=head1 BUGS