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',
+ }
+ },
);
SL::DB::Helper::Attr::make(__PACKAGE__, daily_exchangerate => 'numeric');
}
sub deliverydate {
- # oe doesn't have deliverydate, but PTC checks for deliverydate or transdate to determine tax
- # oe can't deal with deviating tax rates, but at least make sure PTC doesn't barf
- return shift->transdate;
+ # 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';
}
sub effective_tax_point {
my ($self) = @_;
- return $self->tax_point || $self->transdate;
+ return $self->tax_point || $self->deliverydate || $self->transdate;
}
sub displayable_type {
my $invoice;
if (!$self->db->with_transaction(sub {
require SL::DB::Invoice;
- $invoice = SL::DB::Invoice->new_from($self)->post(%params) || die;
+ $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(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;
})) {
}
}
- $self->update_attributes(delivered => 1);
+ $self->update_attributes(delivered => 1) unless $::instance_conf->get_shipped_qty_require_stock_out;
1;
})) {
return undef;
{ from => 'purchase_order', to => 'purchase_order', abbr => 'popo' },
{ from => 'sales_order', to => 'purchase_order', abbr => 'sopo' },
{ from => 'purchase_order', to => 'sales_order', abbr => 'poso' },
+ { from => 'sales_order', to => 'sales_quotation', abbr => 'sosq' },
+ { from => 'purchase_order', to => 'request_quotation', abbr => 'porq' },
);
my $from_to = (grep { $_->{from} eq $source->type && $_->{to} eq $destination_type} @from_tos)[0];
croak("Cannot convert from '" . $source->type . "' to '" . $destination_type . "'") if !$from_to;
my $is_abbr_any = sub {
- # foreach my $abbr (@_) {
- # croak "no such abbreviation: '$abbr'" if !grep { $_->{abbr} eq $abbr } @from_tos;
- # }
any { $from_to->{abbr} eq $_ } @_;
};
}
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 exchangerate 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
+ 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
)),
quotation => !!($destination_type =~ m{quotation$}),
closed => 0,
delivered => 0,
transdate => DateTime->today_local,
+ employee => SL::DB::Manager::Employee->current,
);
if ( $is_abbr_any->(qw(sopo poso)) ) {
$args{ordnumber} = undef;
$args{quonumber} = undef;
$args{reqdate} = DateTime->today_local->next_workday();
- $args{employee} = SL::DB::Manager::Employee->current;
}
if ( $is_abbr_any->(qw(sopo)) ) {
$args{customer_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(sosq porq)) ) {
+ $args{ordnumber} = undef;
+ $args{quonumber} = undef;
+ $args{reqdate} = DateTime->today_local->next_workday();
+ }
# Custom shipto addresses (the ones specific to the sales/purchase
# record and not to the customer/vendor) are only linked from
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
)),
custom_variables => \@custom_variables,
);
# set this entries to undef that yield different information
my %attributes;
- foreach my $attr (qw(ordnumber transdate reqdate taxincluded shippingpoint
+ foreach my $attr (qw(ordnumber transdate reqdate tax_point taxincluded shippingpoint
shipvia notes closed delivered reqdate quonumber
cusordnumber proforma transaction_description
order_probability expected_billing_date)) {
$attributes{$attr} = undef if any { ($sources->[0]->$attr//'') ne ($_->$attr//'') } @$sources;
}
- foreach my $attr (qw(cp_id currency_id employee_id salesman_id department_id
+ foreach my $attr (qw(cp_id currency_id salesman_id department_id
delivery_customer_id delivery_vendor_id shipto_id
globalproject_id exchangerate)) {
$attributes{$attr} = undef if any { ($sources->[0]->$attr||0) != ($_->$attr||0) } @$sources;
# no periodic invoice config for new order
$attributes{periodic_invoices_config} = undef;
+ # set emplyee to the current one
+ $attributes{employee} = SL::DB::Manager::Employee->current;
+
# copy global ordnumber, transdate, cusordnumber into item scope
# unless already present there
foreach my $attr (qw(ordnumber transdate cusordnumber)) {
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::post>.
+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