| 
    
       package SL::DB::Order;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       use utf8;
 
     | 
  
  
     | 
    
       use strict;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       use Carp;
 
     | 
  
  
     | 
    
       use DateTime;
 
     | 
  
  
     | 
    
       use List::Util qw(max);
 
     | 
  
  
     | 
    
       use List::MoreUtils qw(any);
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       use SL::DBUtils ();
 
     | 
  
  
     | 
    
       use SL::DB::PurchaseBasketItem;
 
     | 
  
  
     | 
    
       use SL::DB::MetaSetup::Order;
 
     | 
  
  
     | 
    
       use SL::DB::Manager::Order;
 
     | 
  
  
     | 
    
       use SL::DB::Helper::Attr;
 
     | 
  
  
     | 
    
       use SL::DB::Helper::AttrHTML;
 
     | 
  
  
     | 
    
       use SL::DB::Helper::AttrSorted;
 
     | 
  
  
     | 
    
       use SL::DB::Helper::FlattenToForm;
 
     | 
  
  
     | 
    
       use SL::DB::Helper::LinkedRecords;
 
     | 
  
  
     | 
    
       use SL::DB::Helper::PriceTaxCalculator;
 
     | 
  
  
     | 
    
       use SL::DB::Helper::PriceUpdater;
 
     | 
  
  
     | 
    
       use SL::DB::Helper::TypeDataProxy;
 
     | 
  
  
     | 
    
       use SL::DB::Helper::TransNumberGenerator;
 
     | 
  
  
     | 
    
       use SL::DB::Helper::Payment qw(forex);
 
     | 
  
  
     | 
    
       use SL::DB::Helper::RecordLink qw(RECORD_ID RECORD_TYPE_REF RECORD_ITEM_ID RECORD_ITEM_TYPE_REF);
 
     | 
  
  
     | 
    
       use SL::Helper::KIX18 qw(:all);
 
     | 
  
  
     | 
    
       use SL::Locale::String qw(t8);
 
     | 
  
  
     | 
    
       use SL::RecordLinks;
 
     | 
  
  
     | 
    
       use Rose::DB::Object::Helpers qw(as_tree strip);
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       use SL::DB::Order::TypeData qw(:types validate_type);
 
     | 
  
  
     | 
    
       use SL::DB::Reclamation::TypeData qw(:types);
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       __PACKAGE__->meta->add_relationship(
 
     | 
  
  
     | 
    
         orderitems => {
 
     | 
  
  
     | 
    
           type         => 'one to many',
 
     | 
  
  
     | 
    
           class        => 'SL::DB::OrderItem',
 
     | 
  
  
     | 
    
           column_map   => { id => 'trans_id' },
 
     | 
  
  
     | 
    
           manager_args => {
 
     | 
  
  
     | 
    
             with_objects => [ 'part' ]
 
     | 
  
  
     | 
    
           }
 
     | 
  
  
     | 
    
         },
 
     | 
  
  
     | 
    
         periodic_invoices_config => {
 
     | 
  
  
     | 
    
           type                   => 'one to one',
 
     | 
  
  
     | 
    
           class                  => 'SL::DB::PeriodicInvoicesConfig',
 
     | 
  
  
     | 
    
           column_map             => { id => 'oe_id' },
 
     | 
  
  
     | 
    
         },
 
     | 
  
  
     | 
    
         custom_shipto            => {
 
     | 
  
  
     | 
    
           type                   => 'one to one',
 
     | 
  
  
     | 
    
           class                  => 'SL::DB::Shipto',
 
     | 
  
  
     | 
    
           column_map             => { id => 'trans_id' },
 
     | 
  
  
     | 
    
           query_args             => [ module => 'OE' ],
 
     | 
  
  
     | 
    
         },
 
     | 
  
  
     | 
    
         exchangerate_obj         => {
 
     | 
  
  
     | 
    
           type                   => 'one to one',
 
     | 
  
  
     | 
    
           class                  => 'SL::DB::Exchangerate',
 
     | 
  
  
     | 
    
           column_map             => { currency_id => 'currency_id', transdate => 'transdate' },
 
     | 
  
  
     | 
    
         },
 
     | 
  
  
     | 
    
         phone_notes => {
 
     | 
  
  
     | 
    
           type         => 'one to many',
 
     | 
  
  
     | 
    
           class        => 'SL::DB::Note',
 
     | 
  
  
     | 
    
           column_map   => { id => 'trans_id' },
 
     | 
  
  
     | 
    
           query_args   => [ trans_module => 'oe' ],
 
     | 
  
  
     | 
    
           manager_args => {
 
     | 
  
  
     | 
    
             with_objects => [ 'employee' ],
 
     | 
  
  
     | 
    
             sort_by      => 'notes.itime',
 
     | 
  
  
     | 
    
           }
 
     | 
  
  
     | 
    
         },
 
     | 
  
  
     | 
    
         order_version => {
 
     | 
  
  
     | 
    
           type                   => 'one to many',
 
     | 
  
  
     | 
    
           class                  => 'SL::DB::OrderVersion',
 
     | 
  
  
     | 
    
           column_map             => { id => 'oe_id' },
 
     | 
  
  
     | 
    
         },
 
     | 
  
  
     | 
    
       );
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       SL::DB::Helper::Attr::make(__PACKAGE__, daily_exchangerate => 'numeric');
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       __PACKAGE__->meta->initialize;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       __PACKAGE__->attr_html('notes');
 
     | 
  
  
     | 
    
       __PACKAGE__->attr_sorted('items');
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       __PACKAGE__->before_save('_before_save_set_ord_quo_number');
 
     | 
  
  
     | 
    
       __PACKAGE__->before_save('_before_save_create_new_project');
 
     | 
  
  
     | 
    
       __PACKAGE__->before_save('_before_save_remove_empty_custom_shipto');
 
     | 
  
  
     | 
    
       __PACKAGE__->before_save('_before_save_set_custom_shipto_module');
 
     | 
  
  
     | 
    
       __PACKAGE__->after_save('_after_save_link_records');
 
     | 
  
  
     | 
    
       __PACKAGE__->after_save('_after_save_close_reachable_intakes'); # uses linked records (order matters)
 
     | 
  
  
     | 
    
       __PACKAGE__->before_save('_before_save_delete_from_purchase_basket');
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       # hooks
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub _before_save_set_ord_quo_number {
 
     | 
  
  
     | 
    
         my ($self) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         # ordnumber is 'NOT NULL'. Therefore make sure it's always set to at
 
     | 
  
  
     | 
    
         # least an empty string, even if we're saving a quotation.
 
     | 
  
  
     | 
    
         $self->ordnumber('') if !$self->ordnumber;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         $self->create_trans_number if !$self->record_number;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return 1;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       sub _before_save_create_new_project {
 
     | 
  
  
     | 
    
         my ($self) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         # force new project, if not set yet
 
     | 
  
  
     | 
    
         if ($::instance_conf->get_order_always_project && !$self->globalproject_id && ($self->type eq SALES_ORDER_TYPE())) {
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
           die t8("Error while creating project with project number of new order number, project number #1 already exists!", $self->ordnumber)
 
     | 
  
  
     | 
    
             if SL::DB::Manager::Project->find_by(projectnumber => $self->ordnumber);
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
           eval {
 
     | 
  
  
     | 
    
             my $new_project = SL::DB::Project->new(
 
     | 
  
  
     | 
    
                 projectnumber     => $self->ordnumber,
 
     | 
  
  
     | 
    
                 description       => $self->customer->name,
 
     | 
  
  
     | 
    
                 customer_id       => $self->customer->id,
 
     | 
  
  
     | 
    
                 active            => 1,
 
     | 
  
  
     | 
    
                 project_type_id   => $::instance_conf->get_project_type_id,
 
     | 
  
  
     | 
    
                 project_status_id => $::instance_conf->get_project_status_id,
 
     | 
  
  
     | 
    
                 );
 
     | 
  
  
     | 
    
              $new_project->save;
 
     | 
  
  
     | 
    
              $self->globalproject_id($new_project->id);
 
     | 
  
  
     | 
    
           } or die t8('Could not create new project #1', $@);
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
         return 1;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub _before_save_remove_empty_custom_shipto {
 
     | 
  
  
     | 
    
         my ($self) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         $self->custom_shipto(undef) if $self->custom_shipto && $self->custom_shipto->is_empty;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return 1;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub _before_save_set_custom_shipto_module {
 
     | 
  
  
     | 
    
         my ($self) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         $self->custom_shipto->module('OE') if $self->custom_shipto;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return 1;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub _after_save_link_records {
 
     | 
  
  
     | 
    
         my ($self) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my @allowed_record_sources = qw(SL::DB::Reclamation SL::DB::Order SL::DB::EmailJournal);
 
     | 
  
  
     | 
    
         my @allowed_item_sources = qw(SL::DB::ReclamationItem SL::DB::OrderItem);
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         SL::DB::Helper::RecordLink::link_records(
 
     | 
  
  
     | 
    
           $self,
 
     | 
  
  
     | 
    
           \@allowed_record_sources,
 
     | 
  
  
     | 
    
           \@allowed_item_sources,
 
     | 
  
  
     | 
    
         );
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return 1;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub _after_save_close_reachable_intakes {
 
     | 
  
  
     | 
    
         my ($self) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         # Close reachable sales order intakes in the from-workflow if this is a sales order
 
     | 
  
  
     | 
    
         if (SALES_ORDER_TYPE() eq $self->type) {
 
     | 
  
  
     | 
    
           my $lr = $self->linked_records(direction => 'from', recursive => 1);
 
     | 
  
  
     | 
    
           $lr    = [grep { 'SL::DB::Order' eq ref $_ && !$_->closed && $_->is_type(SALES_ORDER_INTAKE_TYPE()) } @$lr];
 
     | 
  
  
     | 
    
           if (@$lr) {
 
     | 
  
  
     | 
    
             SL::DB::Manager::Order->update_all(set   => {closed => 1},
 
     | 
  
  
     | 
    
                                                where => [id => [map {$_->id} @$lr]]);
 
     | 
  
  
     | 
    
           }
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return 1;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub _before_save_delete_from_purchase_basket {
 
     | 
  
  
     | 
    
         my ($self) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my @basket_item_ids =
 
     | 
  
  
     | 
    
           grep { defined($_) && $_ ne ''}
 
     | 
  
  
     | 
    
           map { $_->{basket_item_id} }
 
     | 
  
  
     | 
    
           $self->orderitems;
 
     | 
  
  
     | 
    
         return 1 unless scalar @basket_item_ids;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         # check if all items are still in the basket
 
     | 
  
  
     | 
    
         my $basket_item_count = SL::DB::Manager::PurchaseBasketItem->get_all_count(
 
     | 
  
  
     | 
    
           where => [ id => \@basket_item_ids ]
 
     | 
  
  
     | 
    
         );
 
     | 
  
  
     | 
    
         if ($basket_item_count != scalar @basket_item_ids) {
 
     | 
  
  
     | 
    
           die "Error while saving order: some items are not in the purchase basket anymore.";
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         if (scalar @basket_item_ids) {
 
     | 
  
  
     | 
    
           SL::DB::Manager::PurchaseBasketItem->delete_all(
 
     | 
  
  
     | 
    
             where => [ id => \@basket_item_ids]
 
     | 
  
  
     | 
    
           );
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return 1;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       # methods
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub items { goto &orderitems; }
 
     | 
  
  
     | 
    
       sub add_items { goto &add_orderitems; }
 
     | 
  
  
     | 
    
       sub record_number { goto &number; }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub type {
 
     | 
  
  
     | 
    
         my $self = shift;
 
     | 
  
  
     | 
    
         SL::DB::Order::TypeData::validate_type($self->record_type);
 
     | 
  
  
     | 
    
         return $self->record_type;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub is_type {
 
     | 
  
  
     | 
    
         return shift->type eq shift;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub quotation {
 
     | 
  
  
     | 
    
         my $type = $_[0]->type();
 
     | 
  
  
     | 
    
         any { $type eq $_ } (
 
     | 
  
  
     | 
    
           SALES_ORDER_INTAKE_TYPE(),
 
     | 
  
  
     | 
    
           SALES_QUOTATION_TYPE(),
 
     | 
  
  
     | 
    
           REQUEST_QUOTATION_TYPE(),
 
     | 
  
  
     | 
    
           PURCHASE_QUOTATION_INTAKE_TYPE(),
 
     | 
  
  
     | 
    
         );
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub intake {
 
     | 
  
  
     | 
    
         my $type = $_[0]->type();
 
     | 
  
  
     | 
    
         any { $type eq $_ } (
 
     | 
  
  
     | 
    
           SALES_ORDER_INTAKE_TYPE(),
 
     | 
  
  
     | 
    
           PURCHASE_QUOTATION_INTAKE_TYPE(),
 
     | 
  
  
     | 
    
         );
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub deliverydate {
 
     | 
  
  
     | 
    
         # oe doesn't have deliverydate, but it does have reqdate.
 
     | 
  
  
     | 
    
         # But this has a different meaning for sales quotations.
 
     | 
  
  
     | 
    
         # deliverydate can be used to determine tax if tax_point isn't set.
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return $_[0]->reqdate if $_[0]->type ne SALES_QUOTATION_TYPE();
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub effective_tax_point {
 
     | 
  
  
     | 
    
         my ($self) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return $self->tax_point || $self->deliverydate || $self->transdate;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub displayable_type {
 
     | 
  
  
     | 
    
         my ($self) = @_;
 
     | 
  
  
     | 
    
         return $self->type_data->text('type');
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub displayable_name {
 
     | 
  
  
     | 
    
         join ' ', grep $_, map $_[0]->$_, qw(displayable_type record_number);
 
     | 
  
  
     | 
    
       };
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub is_sales {
 
     | 
  
  
     | 
    
         croak 'not an accessor' if @_ > 1;
 
     | 
  
  
     | 
    
         $_[0]->type_data->properties('is_customer');
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub daily_exchangerate {
 
     | 
  
  
     | 
    
         my ($self, $val) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return 1 if $self->currency_id == $::instance_conf->get_currency_id;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my $rate = (any { $self->is_type($_) } (SALES_QUOTATION_TYPE(), SALES_ORDER_TYPE()))      ? 'buy'
 
     | 
  
  
     | 
    
                  : (any { $self->is_type($_) } (REQUEST_QUOTATION_TYPE(), PURCHASE_ORDER_TYPE())) ? 'sell'
 
     | 
  
  
     | 
    
                  : undef;
 
     | 
  
  
     | 
    
         return if !$rate;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         if (defined $val) {
 
     | 
  
  
     | 
    
           croak t8('exchange rate has to be positive') if $val <= 0;
 
     | 
  
  
     | 
    
           if (!$self->exchangerate_obj) {
 
     | 
  
  
     | 
    
             $self->exchangerate_obj(SL::DB::Exchangerate->new(
 
     | 
  
  
     | 
    
               currency_id => $self->currency_id,
 
     | 
  
  
     | 
    
               transdate   => $self->transdate,
 
     | 
  
  
     | 
    
               $rate       => $val,
 
     | 
  
  
     | 
    
             ));
 
     | 
  
  
     | 
    
           } elsif (!defined $self->exchangerate_obj->$rate) {
 
     | 
  
  
     | 
    
             $self->exchangerate_obj->$rate($val);
 
     | 
  
  
     | 
    
           } else {
 
     | 
  
  
     | 
    
             croak t8('exchange rate already exists, no update allowed');
 
     | 
  
  
     | 
    
           }
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
         return $self->exchangerate_obj->$rate if $self->exchangerate_obj;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub invoices {
 
     | 
  
  
     | 
    
         my $self   = shift;
 
     | 
  
  
     | 
    
         my %params = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         if ($self->quotation) {
 
     | 
  
  
     | 
    
           return [];
 
     | 
  
  
     | 
    
         } else {
 
     | 
  
  
     | 
    
           require SL::DB::Invoice;
 
     | 
  
  
     | 
    
           return SL::DB::Manager::Invoice->get_all(
 
     | 
  
  
     | 
    
             query => [
 
     | 
  
  
     | 
    
               ordnumber => $self->ordnumber,
 
     | 
  
  
     | 
    
               @{ $params{query} || [] },
 
     | 
  
  
     | 
    
             ]
 
     | 
  
  
     | 
    
           );
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub displayable_state {
 
     | 
  
  
     | 
    
         my ($self) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return $self->closed ? $::locale->text('closed') : $::locale->text('open');
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub abschlag_invoices {
 
     | 
  
  
     | 
    
         return shift()->invoices(query => [ abschlag => 1 ]);
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub end_invoice {
 
     | 
  
  
     | 
    
         return shift()->invoices(query => [ abschlag => 0 ]);
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       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->update_attributes(closed => 1);
 
     | 
  
  
     | 
    
           1;
 
     | 
  
  
     | 
    
         })) {
 
     | 
  
  
     | 
    
           return undef;
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return $invoice;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub convert_to_delivery_order {
 
     | 
  
  
     | 
    
         my ($self, @args) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my $delivery_order;
 
     | 
  
  
     | 
    
         if (!$self->db->with_transaction(sub {
 
     | 
  
  
     | 
    
           require SL::DB::DeliveryOrder;
 
     | 
  
  
     | 
    
           $delivery_order = SL::DB::DeliveryOrder->new_from($self, @args);
 
     | 
  
  
     | 
    
           $delivery_order->save;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
           $self->update_attributes(delivered => 1) unless $::instance_conf->get_shipped_qty_require_stock_out;
 
     | 
  
  
     | 
    
           1;
 
     | 
  
  
     | 
    
         })) {
 
     | 
  
  
     | 
    
           return undef;
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return $delivery_order;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub convert_to_reclamation {
 
     | 
  
  
     | 
    
         my ($self, %params) = @_;
 
     | 
  
  
     | 
    
         $params{destination_type} = $self->is_sales ? SALES_RECLAMATION_TYPE()
 
     | 
  
  
     | 
    
                                                     : PURCHASE_RECLAMATION_TYPE();
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         require SL::DB::Reclamation;
 
     | 
  
  
     | 
    
         my $reclamation = SL::DB::Reclamation->new_from($self, %params);
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return $reclamation;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub _clone_orderitem_cvar {
 
     | 
  
  
     | 
    
         my ($cvar) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my $cloned = $_->clone_and_reset;
 
     | 
  
  
     | 
    
         $cloned->sub_module('orderitems');
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return $cloned;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub create_from_purchase_basket {
 
     | 
  
  
     | 
    
         my ($class, $basket_item_ids, $vendor_item_ids, $vendor_id) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my ($vendor, $employee);
 
     | 
  
  
     | 
    
         $vendor   = SL::DB::Manager::Vendor->find_by(id => $vendor_id);
 
     | 
  
  
     | 
    
         $employee = SL::DB::Manager::Employee->current;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my @orderitem_maps = (); # part, qty, orderer_id
 
     | 
  
  
     | 
    
         if ($basket_item_ids && scalar @{ $basket_item_ids}) {
 
     | 
  
  
     | 
    
           my $basket_items = SL::DB::Manager::PurchaseBasketItem->get_all(
 
     | 
  
  
     | 
    
             query => [ id => $basket_item_ids ],
 
     | 
  
  
     | 
    
             with_objects => ['part'],
 
     | 
  
  
     | 
    
           );
 
     | 
  
  
     | 
    
           push @orderitem_maps, map {{
 
     | 
  
  
     | 
    
               basket_item_id => $_->id,
 
     | 
  
  
     | 
    
               part       => $_->part,
 
     | 
  
  
     | 
    
               qty        => $_->qty,
 
     | 
  
  
     | 
    
               orderer_id => $_->orderer_id,
 
     | 
  
  
     | 
    
             }} @{$basket_items};
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
         if ($vendor_item_ids && scalar @{ $vendor_item_ids}) {
 
     | 
  
  
     | 
    
           my $vendor_items = SL::DB::Manager::Part->get_all(
 
     | 
  
  
     | 
    
             query => [ id => $vendor_item_ids ] );
 
     | 
  
  
     | 
    
           push @orderitem_maps, map {{
 
     | 
  
  
     | 
    
               basket_item_id => undef,
 
     | 
  
  
     | 
    
               part       => $_,
 
     | 
  
  
     | 
    
               qty        => $_->order_qty || 1,
 
     | 
  
  
     | 
    
               orderer_id => $employee->id,
 
     | 
  
  
     | 
    
             }} @{$vendor_items};
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my $order = $class->new(
 
     | 
  
  
     | 
    
           vendor_id               => $vendor->id,
 
     | 
  
  
     | 
    
           employee_id             => $employee->id,
 
     | 
  
  
     | 
    
           intnotes                => $vendor->notes,
 
     | 
  
  
     | 
    
           salesman_id             => $employee->id,
 
     | 
  
  
     | 
    
           payment_id              => $vendor->payment_id,
 
     | 
  
  
     | 
    
           delivery_term_id        => $vendor->delivery_term_id,
 
     | 
  
  
     | 
    
           taxzone_id              => $vendor->taxzone_id,
 
     | 
  
  
     | 
    
           currency_id             => $vendor->currency_id,
 
     | 
  
  
     | 
    
           transdate               => DateTime->today_local,
 
     | 
  
  
     | 
    
           record_type             => PURCHASE_ORDER_TYPE(),
 
     | 
  
  
     | 
    
         );
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my @order_items;
 
     | 
  
  
     | 
    
         my $i = 0;
 
     | 
  
  
     | 
    
         foreach my $orderitem_map (@orderitem_maps) {
 
     | 
  
  
     | 
    
           $i++;
 
     | 
  
  
     | 
    
           my $part = $orderitem_map->{part};
 
     | 
  
  
     | 
    
           my $qty = $orderitem_map->{qty};
 
     | 
  
  
     | 
    
           my $orderer_id = $orderitem_map->{orderer_id};
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
           my $order_item = SL::DB::OrderItem->new(
 
     | 
  
  
     | 
    
             part                => $part,
 
     | 
  
  
     | 
    
             qty                 => $qty,
 
     | 
  
  
     | 
    
             unit                => $part->unit,
 
     | 
  
  
     | 
    
             description         => $part->description,
 
     | 
  
  
     | 
    
             price_factor_id     => $part->price_factor_id,
 
     | 
  
  
     | 
    
             price_factor        =>
 
     | 
  
  
     | 
    
               $part->price_factor_id ? $part->price_factor->factor
 
     | 
  
  
     | 
    
                                      : '',
 
     | 
  
  
     | 
    
             orderer_id          => $orderer_id,
 
     | 
  
  
     | 
    
             position            => $i,
 
     | 
  
  
     | 
    
           );
 
     | 
  
  
     | 
    
           $order_item->{basket_item_id} = $orderitem_map->{basket_item_id};
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
           my $price_source  = SL::PriceSource->new(
 
     | 
  
  
     | 
    
             record_item => $order_item, record => $order);
 
     | 
  
  
     | 
    
           $order_item->sellprice(
 
     | 
  
  
     | 
    
             $price_source->best_price ? $price_source->best_price->price
 
     | 
  
  
     | 
    
                                       : 0);
 
     | 
  
  
     | 
    
           $order_item->active_price_source(
 
     | 
  
  
     | 
    
             $price_source->best_price ? $price_source->best_price->source
 
     | 
  
  
     | 
    
                                       : '');
 
     | 
  
  
     | 
    
           push @order_items, $order_item;
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         $order->assign_attributes(orderitems => \@order_items);
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         $order->calculate_prices_and_taxes;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         foreach my $item(@{ $order->orderitems }){
 
     | 
  
  
     | 
    
           $item->parse_custom_variable_values;
 
     | 
  
  
     | 
    
           $item->{custom_variables} = \@{ $item->cvars_by_config };
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         return $order;
 
     | 
  
  
     | 
    
       }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       sub new_from {
 
     | 
  
  
     | 
    
         my ($class, $source, %params) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         unless (any {ref($source) eq $_} qw(
 
     | 
  
  
     | 
    
           SL::DB::Order
 
     | 
  
  
     | 
    
           SL::DB::Reclamation
 
     | 
  
  
     | 
    
         )) {
 
     | 
  
  
     | 
    
           croak("Unsupported source object type '" . ref($source) . "'");
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
         croak("A destination type must be given as parameter")         unless $params{destination_type};
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my $destination_type  = delete $params{destination_type};
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my @from_tos = (
 
     | 
  
  
     | 
    
           { from => SALES_QUOTATION_TYPE(),             to => SALES_ORDER_TYPE(),                 abbr => 'sqso'   },
 
     | 
  
  
     | 
    
           { from => REQUEST_QUOTATION_TYPE(),           to => PURCHASE_ORDER_TYPE(),              abbr => 'rqpo'   },
 
     | 
  
  
     | 
    
           { from => SALES_QUOTATION_TYPE(),             to => SALES_QUOTATION_TYPE(),             abbr => 'sqsq'   },
 
     | 
  
  
     | 
    
           { from => SALES_ORDER_TYPE(),                 to => SALES_ORDER_TYPE(),                 abbr => 'soso'   },
 
     | 
  
  
     | 
    
           { from => REQUEST_QUOTATION_TYPE(),           to => REQUEST_QUOTATION_TYPE(),           abbr => 'rqrq'   },
 
     | 
  
  
     | 
    
           { from => PURCHASE_ORDER_TYPE(),              to => PURCHASE_ORDER_TYPE(),              abbr => 'popo'   },
 
     | 
  
  
     | 
    
           { from => SALES_ORDER_TYPE(),                 to => PURCHASE_ORDER_TYPE(),              abbr => 'sopo'   },
 
     | 
  
  
     | 
    
           { from => PURCHASE_ORDER_TYPE(),              to => SALES_ORDER_TYPE(),                 abbr => 'poso'   },
 
     | 
  
  
     | 
    
           { from => SALES_ORDER_TYPE(),                 to => SALES_QUOTATION_TYPE(),             abbr => 'sosq'   },
 
     | 
  
  
     | 
    
           { from => PURCHASE_ORDER_TYPE(),              to => REQUEST_QUOTATION_TYPE(),           abbr => 'porq'   },
 
     | 
  
  
     | 
    
           { from => REQUEST_QUOTATION_TYPE(),           to => SALES_QUOTATION_TYPE(),             abbr => 'rqsq'   },
 
     | 
  
  
     | 
    
           { from => REQUEST_QUOTATION_TYPE(),           to => SALES_ORDER_TYPE(),                 abbr => 'rqso'   },
 
     | 
  
  
     | 
    
           { from => SALES_QUOTATION_TYPE(),             to => REQUEST_QUOTATION_TYPE(),           abbr => 'sqrq'   },
 
     | 
  
  
     | 
    
           { from => SALES_ORDER_TYPE(),                 to => REQUEST_QUOTATION_TYPE(),           abbr => 'sorq'   },
 
     | 
  
  
     | 
    
           { from => SALES_RECLAMATION_TYPE(),           to => SALES_ORDER_TYPE(),                 abbr => 'srso'   },
 
     | 
  
  
     | 
    
           { from => PURCHASE_RECLAMATION_TYPE(),        to => PURCHASE_ORDER_TYPE(),              abbr => 'prpo'   },
 
     | 
  
  
     | 
    
           { from => SALES_ORDER_INTAKE_TYPE(),          to => SALES_ORDER_INTAKE_TYPE(),          abbr => 'soisoi' },
 
     | 
  
  
     | 
    
           { from => SALES_ORDER_INTAKE_TYPE(),          to => SALES_QUOTATION_TYPE(),             abbr => 'soisq'  },
 
     | 
  
  
     | 
    
           { from => SALES_ORDER_INTAKE_TYPE(),          to => REQUEST_QUOTATION_TYPE(),           abbr => 'soirq'  },
 
     | 
  
  
     | 
    
           { from => SALES_ORDER_INTAKE_TYPE(),          to => SALES_ORDER_TYPE(),                 abbr => 'soiso'  },
 
     | 
  
  
     | 
    
           { from => SALES_ORDER_INTAKE_TYPE(),          to => PURCHASE_ORDER_TYPE(),              abbr => 'soipo'  },
 
     | 
  
  
     | 
    
           { from => SALES_QUOTATION_TYPE(),             to => SALES_ORDER_INTAKE_TYPE(),          abbr => 'sqsoi'  },
 
     | 
  
  
     | 
    
           { from => PURCHASE_QUOTATION_INTAKE_TYPE(),   to => PURCHASE_QUOTATION_INTAKE_TYPE(),   abbr => 'pqipqi' },
 
     | 
  
  
     | 
    
           { from => PURCHASE_QUOTATION_INTAKE_TYPE(),   to => SALES_QUOTATION_TYPE(),             abbr => 'pqisq'  },
 
     | 
  
  
     | 
    
           { from => PURCHASE_QUOTATION_INTAKE_TYPE(),   to => SALES_ORDER_TYPE(),                 abbr => 'pqiso'  },
 
     | 
  
  
     | 
    
           { from => PURCHASE_QUOTATION_INTAKE_TYPE(),   to => PURCHASE_ORDER_TYPE(),              abbr => 'pqipo'  },
 
     | 
  
  
     | 
    
           { from => REQUEST_QUOTATION_TYPE(),           to => PURCHASE_QUOTATION_INTAKE_TYPE(),   abbr => 'rqpqi'  },
 
     | 
  
  
     | 
    
           { from => PURCHASE_ORDER_CONFIRMATION_TYPE(), to => PURCHASE_ORDER_CONFIRMATION_TYPE(), abbr => 'pocpoc' },
 
     | 
  
  
     | 
    
           { from => PURCHASE_ORDER_CONFIRMATION_TYPE(), to => SALES_QUOTATION_TYPE(),             abbr => 'pocsq' },
 
     | 
  
  
     | 
    
           { from => PURCHASE_ORDER_CONFIRMATION_TYPE(), to => SALES_ORDER_TYPE(),                 abbr => 'pocso' },
 
     | 
  
  
     | 
    
           { from => PURCHASE_ORDER_CONFIRMATION_TYPE(), to => PURCHASE_ORDER_TYPE(),              abbr => 'pocpo' },
 
     | 
  
  
     | 
    
           { from => PURCHASE_ORDER_TYPE(),              to => PURCHASE_ORDER_CONFIRMATION_TYPE(), abbr => 'popoc' },
 
     | 
  
  
     | 
    
         );
 
     | 
  
  
     | 
    
         my $from_to = (grep { $_->{from} eq $source->record_type && $_->{to} eq $destination_type} @from_tos)[0];
 
     | 
  
  
     | 
    
         croak("Cannot convert from '" . $source->record_type . "' to '" . $destination_type . "'") if !$from_to;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my $is_abbr_any = sub {
 
     | 
  
  
     | 
    
           my (@abbrs) = @_;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
           my $missing_abbr;
 
     | 
  
  
     | 
    
           if (any { $missing_abbr = $_; !grep { $_->{abbr} eq $missing_abbr } @from_tos } @abbrs) {
 
     | 
  
  
     | 
    
             die "no such workflow abbreviation '$missing_abbr'";
 
     | 
  
  
     | 
    
           }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
           any { $from_to->{abbr} eq $_ } @abbrs;
 
     | 
  
  
     | 
    
         };
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my %args;
 
     | 
  
  
     | 
    
         if (ref($source) eq 'SL::DB::Order') {
 
     | 
  
  
     | 
    
           %args = ( map({ ( $_ => $source->$_ ) } qw(amount cp_id currency_id cusordnumber customer_id delivery_customer_id delivery_term_id delivery_vendor_id
 
     | 
  
  
     | 
    
                                                      department_id exchangerate globalproject_id intnotes marge_percent marge_total language_id netamount notes
 
     | 
  
  
     | 
    
                                                      ordnumber payment_id quonumber reqdate salesman_id shippingpoint shipvia taxincluded tax_point taxzone_id
 
     | 
  
  
     | 
    
                                                      transaction_description vendor_id billing_address_id
 
     | 
  
  
     | 
    
                                                   )),
 
     | 
  
  
     | 
    
                        closed    => 0,
 
     | 
  
  
     | 
    
                        delivered => 0,
 
     | 
  
  
     | 
    
                        transdate => DateTime->today_local,
 
     | 
  
  
     | 
    
                        employee  => SL::DB::Manager::Employee->current,
 
     | 
  
  
     | 
    
                     );
 
     | 
  
  
     | 
    
           # reqdate in quotation is 'offer is valid    until reqdate'
 
     | 
  
  
     | 
    
           # reqdate in order     is 'will be delivered until reqdate'
 
     | 
  
  
     | 
    
           # both dates are setable (on|off)
 
     | 
  
  
     | 
    
           # and may have a additional interval in days (+ n days)
 
     | 
  
  
     | 
    
           # dies if this convention will change
 
     | 
  
  
     | 
    
           $args{reqdate} = $from_to->{to} =~ m/_quotation$/
 
     | 
  
  
     | 
    
                          ? $::instance_conf->get_reqdate_on
 
     | 
  
  
     | 
    
                          ? DateTime->today_local->next_workday(extra_days => $::instance_conf->get_reqdate_interval)->to_kivitendo
 
     | 
  
  
     | 
    
                          : undef
 
     | 
  
  
     | 
    
                          : $from_to->{to} =~ m/_order$/
 
     | 
  
  
     | 
    
                          ? $::instance_conf->get_deliverydate_on
 
     | 
  
  
     | 
    
                          ? DateTime->today_local->next_workday(extra_days => $::instance_conf->get_delivery_date_interval)->to_kivitendo
 
     | 
  
  
     | 
    
                          : undef
 
     | 
  
  
     | 
    
                          : $from_to->{to} =~ m/^sales_order_intake$/
 
     | 
  
  
     | 
    
                          # ? $source->reqdate
 
     | 
  
  
     | 
    
                          ? undef
 
     | 
  
  
     | 
    
                          : $from_to->{to} =~ m/^purchase_quotation_intake$/
 
     | 
  
  
     | 
    
                          ? $source->reqdate
 
     | 
  
  
     | 
    
                          : $from_to->{to} =~ m/^purchase_order_confirmation$/
 
     | 
  
  
     | 
    
                          ? $source->reqdate
 
     | 
  
  
     | 
    
                          : die "Wrong state for reqdate";
 
     | 
  
  
     | 
    
         } elsif ( ref($source) eq 'SL::DB::Reclamation') {
 
     | 
  
  
     | 
    
           %args = ( map({ ( $_ => $source->$_ ) } qw(
 
     | 
  
  
     | 
    
               amount billing_address_id currency_id customer_id delivery_term_id department_id
 
     | 
  
  
     | 
    
               exchangerate globalproject_id intnotes language_id netamount
 
     | 
  
  
     | 
    
               notes payment_id  reqdate salesman_id shippingpoint shipvia taxincluded
 
     | 
  
  
     | 
    
               tax_point taxzone_id transaction_description vendor_id
 
     | 
  
  
     | 
    
             )),
 
     | 
  
  
     | 
    
             cp_id     => $source->{contact_id},
 
     | 
  
  
     | 
    
             closed    => 0,
 
     | 
  
  
     | 
    
             delivered => 0,
 
     | 
  
  
     | 
    
             transdate => DateTime->today_local,
 
     | 
  
  
     | 
    
             employee  => SL::DB::Manager::Employee->current,
 
     | 
  
  
     | 
    
          );
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         if ( $is_abbr_any->(qw(soipo sopo poso rqso soisq sosq porq rqsq sqrq soirq sorq pqisq pqiso pocsq pocso)) ) {
 
     | 
  
  
     | 
    
           $args{ordnumber} = undef;
 
     | 
  
  
     | 
    
           $args{quonumber} = undef;
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
         if ( $is_abbr_any->(qw(soipo sopo sqrq soirq sorq)) ) {
 
     | 
  
  
     | 
    
           $args{customer_id}      = undef;
 
     | 
  
  
     | 
    
           $args{salesman_id}      = undef;
 
     | 
  
  
     | 
    
           $args{payment_id}       = undef;
 
     | 
  
  
     | 
    
           $args{delivery_term_id} = undef;
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
         if ( $is_abbr_any->(qw(poso rqsq pqisq pqiso pocsq pocso)) ) {
 
     | 
  
  
     | 
    
           $args{vendor_id} = undef;
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
         if ( $is_abbr_any->(qw(soso)) ) {
 
     | 
  
  
     | 
    
           $args{periodic_invoices_config} = $source->periodic_invoices_config->clone_and_reset if $source->periodic_invoices_config;
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
         if ( $is_abbr_any->(qw(sqrq soirq sorq)) ) {
 
     | 
  
  
     | 
    
           $args{cusordnumber} = undef;
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
         if ( $is_abbr_any->(qw(soiso pocpoc pocpo popoc)) ) {
 
     | 
  
  
     | 
    
           $args{ordnumber} = undef;
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
         if ( $is_abbr_any->(qw(rqpqi pqisq)) ) {
 
     | 
  
  
     | 
    
           $args{quonumber} = undef;
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         # 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;
 
     | 
  
  
     | 
    
         }
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         $args{record_type} = $destination_type;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my $order = $class->new(%args);
 
     | 
  
  
     | 
    
         $order->assign_attributes(%{ $params{attributes} }) if $params{attributes};
 
     | 
  
  
     | 
    
         my $items = delete($params{items}) || $source->items_sorted;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
         my @items = map {
 
     | 
  
  
     | 
    
           my $source_item      = $_;
 
     | 
  
  
     | 
    
           my @custom_variables = map { _clone_orderitem_cvar($_) } @{ $source_item->custom_variables };
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
           my $current_oe_item;
 
     | 
  
  
     | 
    
           if (ref($source) eq 'SL::DB::Order') {
 
     | 
  
  
     | 
    
             $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
 
     | 
  
  
     | 
    
                                                                 optional recurring_billing_mode position
 
     | 
  
  
     | 
    
                                                              )),
 
     | 
  
  
     | 
    
                                                          custom_variables => \@custom_variables,
 
     | 
  
  
     | 
    
             );
 
     | 
  
  
     | 
    
           } elsif (ref($source) eq 'SL::DB::Reclamation') {
 
     | 
  
  
     | 
    
             $current_oe_item = SL::DB::OrderItem->new(
 
     | 
  
  
     | 
    
               map({ ( $_ => $source_item->$_ ) } qw(
 
     | 
  
  
     | 
    
                 active_discount_source active_price_source base_qty description
 
     | 
  
  
     | 
    
                 discount lastcost longdescription parts_id price_factor
 
     | 
  
  
     | 
    
                 price_factor_id pricegroup_id project_id qty reqdate sellprice
 
     | 
  
  
     | 
    
                 serialnumber unit position
 
     | 
  
  
     | 
    
               )),
 
     | 
  
  
     | 
    
               custom_variables => \@custom_variables,
 
     | 
  
  
     | 
    
             );
 
     | 
  
  
     | 
    
           }
 
     | 
  
  
     | 
    
           if ( $is_abbr_any->(qw(soipo sopo)) ) {
 
     | 
  
  
     | 
    
             $current_oe_item  |