|
package SL::DB::Reclamation;
|
|
|
|
use utf8;
|
|
use strict;
|
|
|
|
use Carp;
|
|
use DateTime;
|
|
use List::Util qw(max sum0);
|
|
use List::MoreUtils qw(any);
|
|
|
|
use SL::DB::MetaSetup::Reclamation;
|
|
use SL::DB::Manager::Reclamation;
|
|
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::TransNumberGenerator;
|
|
use SL::Locale::String qw(t8);
|
|
use SL::RecordLinks;
|
|
use Rose::DB::Object::Helpers qw(as_tree);
|
|
|
|
__PACKAGE__->meta->add_relationship(
|
|
|
|
reclamation_items => {
|
|
type => 'one to many',
|
|
class => 'SL::DB::ReclamationItem',
|
|
column_map => { id => 'reclamation_id' },
|
|
manager_args => {
|
|
with_objects => [ 'part', 'reason' ]
|
|
}
|
|
},
|
|
custom_shipto => {
|
|
type => 'one to one',
|
|
class => 'SL::DB::Shipto',
|
|
column_map => { id => 'trans_id' },
|
|
query_args => [ module => 'Reclamation' ],
|
|
},
|
|
exchangerate_obj => {
|
|
type => 'one to one',
|
|
class => 'SL::DB::Exchangerate',
|
|
column_map => { currency_id => 'currency_id', transdate => 'transdate' },
|
|
},
|
|
);
|
|
|
|
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_record_number');
|
|
__PACKAGE__->before_save('_before_save_remove_empty_custom_shipto');
|
|
__PACKAGE__->before_save('_before_save_set_custom_shipto_module');
|
|
|
|
# hooks
|
|
|
|
sub _before_save_set_record_number {
|
|
my ($self) = @_;
|
|
|
|
$self->create_trans_number if !$self->record_number;
|
|
|
|
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('Reclamation') if $self->custom_shipto;
|
|
|
|
return 1;
|
|
}
|
|
|
|
# methods
|
|
|
|
sub items { goto &reclamation_items; }
|
|
sub add_items { goto &add_reclamation_items; }
|
|
sub record_items { goto &reclamation_items; }
|
|
|
|
sub type {
|
|
my ($self) = @_;
|
|
|
|
return 'sales_reclamation' if $self->customer_id;
|
|
return 'purchase_reclamation' if $self->vendor_id;
|
|
|
|
return;
|
|
}
|
|
|
|
sub is_type {
|
|
my ($self, $type) = @_;
|
|
return $self->type eq $type;
|
|
}
|
|
|
|
sub effective_tax_point {
|
|
my ($self) = @_;
|
|
|
|
return $self->tax_point || $self->reqdate || $self->transdate;
|
|
}
|
|
|
|
sub displayable_type {
|
|
my $type = shift->type;
|
|
|
|
return $::locale->text('Sales Reclamation') if $type eq 'sales_reclamation';
|
|
return $::locale->text('Purchase Reclamation') if $type eq 'purchase_reclamation';
|
|
|
|
die 'invalid type';
|
|
}
|
|
|
|
sub displayable_name {
|
|
join ' ', grep $_, map $_[0]->$_, qw(displayable_type record_number);
|
|
};
|
|
|
|
sub is_sales {
|
|
croak 'not an accessor' if @_ > 1;
|
|
return !!shift->customer_id;
|
|
}
|
|
|
|
sub daily_exchangerate {
|
|
my ($self, $val) = @_;
|
|
|
|
return 1 if $self->currency_id == $::instance_conf->get_currency_id;
|
|
|
|
my $rate = (any { $self->is_type($_) } qw(sales_reclamation)) ? 'buy'
|
|
: (any { $self->is_type($_) } qw(purchase_reclamation)) ? '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 taxes {
|
|
my ($self) = @_;
|
|
# add taxes to recalmation
|
|
my %pat = $self->calculate_prices_and_taxes();
|
|
my @taxes;
|
|
foreach my $tax_id (keys %{ $pat{taxes_by_tax_id} }) {
|
|
my $netamount = sum0 map { $pat{amounts}->{$_}->{amount} } grep { $pat{amounts}->{$_}->{tax_id} == $tax_id } keys %{ $pat{amounts} };
|
|
push(@taxes, { amount => $pat{taxes_by_tax_id}->{$tax_id},
|
|
netamount => $netamount,
|
|
tax => SL::DB::Tax->new(id => $tax_id)->load });
|
|
}
|
|
return \@taxes;
|
|
}
|
|
|
|
sub displayable_state {
|
|
my ($self) = @_;
|
|
|
|
return $self->closed ? $::locale->text('closed') : $::locale->text('open');
|
|
}
|
|
|
|
sub valid_reclamation_reasons {
|
|
my ($self) = @_;
|
|
|
|
my $valid_for_type = ($self->type =~ m{sales} ? 'valid_for_sales' : 'valid_for_purchase');
|
|
return SL::DB::Manager::ReclamationReason->get_all_sorted(
|
|
where => [ $valid_for_type => 1 ]);
|
|
}
|
|
|
|
sub convert_to_order {
|
|
my ($self, %params) = @_;
|
|
|
|
my $order;
|
|
$params{destination_type} = $self->is_sales ? 'sales_order'
|
|
: 'purchase_order';
|
|
if (!$self->db->with_transaction(sub {
|
|
require SL::DB::Order;
|
|
$order = SL::DB::Order->new_from($self, %params);
|
|
$order->save;
|
|
$self->link_to_record($order);
|
|
foreach my $item (@{ $order->items }) {
|
|
foreach (qw(reclamation_item)) {
|
|
if ($item->{"converted_from_${_}_id"}) {
|
|
die unless $item->{id};
|
|
RecordLinks->create_links('dbh' => $self->db->dbh,
|
|
'mode' => 'ids',
|
|
'from_table' => 'reclamation_items',
|
|
'from_ids' => $item->{"converted_from_${_}_id"},
|
|
'to_table' => 'orderitems',
|
|
'to_id' => $item->{id},
|
|
) || die;
|
|
delete $item->{"converted_from_${_}_id"};
|
|
}
|
|
}
|
|
}
|
|
|
|
1;
|
|
})) {
|
|
return undef;
|
|
}
|
|
|
|
return $order;
|
|
}
|
|
|
|
sub convert_to_delivery_order {
|
|
my ($self, %params) = @_;
|
|
|
|
my $delivery_order;
|
|
if (!$self->db->with_transaction(sub {
|
|
require SL::DB::DeliveryOrder;
|
|
$delivery_order = SL::DB::DeliveryOrder->new_from($self, %params);
|
|
$delivery_order->save;
|
|
$self->link_to_record($delivery_order);
|