Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision a7ca8ba2

Von Jan Büren vor mehr als 9 Jahren hinzugefügt

  • ID a7ca8ba215c2a039e97c27bc3c637712fca837e9
  • Vorgänger 46c987b8
  • Nachfolger f515825d

DeliveryOrder um convert_invoice erweitert

Diesselbe Idee wie bei SalesOrder->convert_invoice. Der ursprüngliche
Lieferschein wird geschlossen und das neue Objekt mittels record_links
verknüpft.
Entsprechend Testfall mitgeliefert.

Unterschiede anzeigen:

SL/DB/DeliveryOrder.pm
$_[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)->post(%params) || die;
$self->link_to_record($invoice);
foreach my $item (@{ $invoice->items }) {
foreach (qw(delivery_order_items)) { # expand if needed (delivery_order_items)
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__
......
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::post>.
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
t/db_helper/convert_invoice.t
use Test::More tests => 29;
use strict;
use lib 't';
use utf8;
use Support::TestSetup;
use Carp;
use Data::Dumper;
use Support::TestSetup;
use Test::Exception;
use List::Util qw(max);
use SL::DB::Buchungsgruppe;
use SL::DB::Currency;
use SL::DB::Customer;
use SL::DB::Employee;
use SL::DB::Invoice;
use SL::DB::Order;
use SL::DB::DeliveryOrder;
use SL::DB::Part;
use SL::DB::Unit;
use SL::DB::TaxZone;
my ($customer, $currency_id, $buchungsgruppe, $employee, $vendor, $taxzone, $buchungsgruppe7, $tax, $tax7,
$unit, @parts);
sub clear_up {
foreach (qw(DeliveryOrderItem DeliveryOrder InvoiceItem Invoice Part Customer Vendor Employee Department PaymentTerm)) {
"SL::DB::Manager::${_}"->delete_all(all => 1);
}
};
sub reset_state {
my %params = @_;
clear_up();
$buchungsgruppe = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 19%', %{ $params{buchungsgruppe} }) || croak "No accounting group 19\%";
$buchungsgruppe7 = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 7%', %{ $params{buchungsgruppe} }) || croak "No accounting group 7\%";
$taxzone = SL::DB::Manager::TaxZone->find_by( description => 'Inland') || croak "No taxzone";
$tax = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19, %{ $params{tax} }) || croak "No tax for 19\%";
$tax7 = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07) || croak "No tax for 7\%";
$unit = SL::DB::Manager::Unit->find_by(name => 'kg', %{ $params{unit} }) || croak "No unit";
$currency_id = $::instance_conf->get_currency_id;
$customer = SL::DB::Customer->new(
name => '520484567dfaedc9e60fc',
currency_id => $currency_id,
taxzone_id => $taxzone->id,
%{ $params{customer} }
)->save;
# some od.rnr real anonym data
my $employee_bk = SL::DB::Employee->new(
'id' => 31915,
'login' => 'barbuschka.kappes',
'name' => 'Barbuschka Kappes',
)->save;
my $department_do = SL::DB::Department->new(
'description' => 'Maisenhaus-Versand',
'id' => 32149,
'itime' => undef,
'mtime' => undef
)->save;
my $payment_do = SL::DB::PaymentTerm->new(
'description' => '14Tage 2%Skonto, 30Tage netto',
'description_long' => "Innerhalb von 14 Tagen abzüglich 2 % Skonto, innerhalb von 30 Tagen rein netto.|Bei einer Zahlung bis zum <%skonto_date%> gewähren wir 2 % Skonto (EUR <%skonto_amount%>) entspricht EUR <%total_wo_skonto%>.Bei einer Zahlung bis zum <%netto_date%> ist der fällige Betrag in Höhe von <%total%> <%currency%> zu überweisen.",
'id' => 11276,
'itime' => undef,
'mtime' => undef,
'percent_skonto' => '0.02',
'ranking' => undef,
'sortkey' => 4,
'terms_netto' => 30,
'auto_calculation' => undef,
'terms_skonto' => 14
)->save;
# two real parts
@parts = ();
push @parts, SL::DB::Part->new(
'id' => 26321,
'image' => '',
'lastcost' => '49.95000',
'listprice' => '0.00000',
'onhand' => '5.00000',
'partnumber' => 'v-519160549',
#'partsgroup_id' => 111645,
'rop' => '0',
'sellprice' => '242.20000',
#'warehouse_id' => 64702,
'weight' => '0.79',
description => "Nussbaum, Gr.5, Unterfilz weinrot, genietet[[Aufschnittbreite: 11,0, Kernform: US]]\"" ,
buchungsgruppen_id => $buchungsgruppe->id,
unit => $unit->name,
id => 26321,
)->save;
push @parts, SL::DB::Part->new(
'description' => "[[0640]]Flügel Hammerstiele bestehend aus:
70 Stielen Standard in Weißbuche und
20 Stielen Diskant abgekehlt in Weißbuche
mit Röllchen aus Synthetikleder,
Kapseln mit Yamaha Profil, Kerbenabstand 3,6 mm mit eingedrehten Abnickschrauben",
'id' => 25505,
'lastcost' => '153.00000',
'listprice' => '0.00000',
'onhand' => '9.00000',
'partnumber' => 'v-120160086',
# 'partsgroup_id' => 111639,
'rop' => '0',
'sellprice' => '344.30000',
'weight' => '0.9',
buchungsgruppen_id => $buchungsgruppe->id,
unit => $unit->name,
)->save;
}
sub new_delivery_order {
my %params = @_;
return SL::DB::DeliveryOrder->new(
currency_id => $currency_id,
taxzone_id => $taxzone->id,
%params,
)->save;
}
Support::TestSetup::login();
reset_state();
# we create L20199 with two items
my $do1 = new_delivery_order('department_id' => 32149,
'donumber' => 'L20199',
'employee_id' => 31915,
'intnotes' => 'Achtung: Neue Lieferadresse ab 16.02.2015 in der Carl-von-Ossietzky-Str.32! 13.02.2015/MH
Steinway-Produkte (201...) immer plus 25% dazu rechnen / BK 13.02.2014',
'ordnumber' => 'A16399',
'payment_id' => 11276,
'salesman_id' => 31915,
'shippingpoint' => 'Maisenhaus',
# 'shipto_id' => 451463,
'is_sales' => 'true',
'shipvia' => 'DHL, Versand am 06.03.2015, 1 Paket 17,00 kg',
'taxzone_id' => 4,
'closed' => undef,
# 'currency_id' => 1,
'cusordnumber' => 'b84da',
'customer_id' => $customer->id,
'id' => 464003,
);
my $do1_item1 = SL::DB::DeliveryOrderItem->new('delivery_order_id' => 464003,
'description' => "Flügel Hammerkopf bestehend aus:
Bass/Diskant 26/65 Stück, Gesamtlänge 80/72, Bohrlänge 56/48
Nussbaum, Gr.5, Unterfilz weinrot, genietet[[Aufschnittbreite: 11,0, Kernform: US]]",
'discount' => '0.25',
'id' => 144736,
'lastcost' => '49.95000',
'longdescription' => '',
'marge_price_factor' => 1,
'mtime' => undef,
'ordnumber' => 'A16399',
'parts_id' => 26321,
'position' => 1,
'price_factor' => 1,
'qty' => '2.00000',
'sellprice' => '242.20000',
'transdate' => '06.03.2015',
'unit' => 'kg')->save;
my $do1_item2 = SL::DB::DeliveryOrderItem->new('delivery_order_id' => 464003,
'description' => "[[0640]]Flügel Hammerstiele bestehend aus:
70 Stielen Standard in Weißbuche und
20 Stielen Diskant abgekehlt in Weißbuche
mit Röllchen aus Synthetikleder,
Kapseln mit Yamaha Profil, Kerbenabstand 3,6 mm mit eingedrehten Abnickschrauben",
'discount' => '0.25',
'id' => 144737,
'itime' => undef,
'lastcost' => '153.00000',
'longdescription' => '',
'marge_price_factor' => 1,
'mtime' => undef,
'ordnumber' => 'A16399',
'parts_id' => 25505,
'position' => 2,
'price_factor' => 1,
'price_factor_id' => undef,
'pricegroup_id' => undef,
'project_id' => undef,
'qty' => '3.00000',
'reqdate' => undef,
'sellprice' => '344.30000',
'serialnumber' => '',
'transdate' => '06.03.2015',
'unit' => 'kg')->save;
# TESTS
# test delivery order before any conversion
ok($do1->donumber eq "L20199", 'Delivery Order Number created');
ok((not $do1->closed) , 'Delivery Order is not closed');
ok($do1_item1->parts_id eq '26321', 'doi linked with part');
ok($do1_item1->qty == 2, 'qty check doi');
ok($do1_item2->position == 2, 'doi2 position check');
ok(2 == scalar@{ SL::DB::Manager::DeliveryOrderItem->get_all(where => [ delivery_order_id => $do1->id ]) }, 'two doi linked');
# convert this do to invoice
my $invoice = $do1->convert_to_invoice();
# test invoice afterwards
ok ($invoice->shipvia eq "DHL, Versand am 06.03.2015, 1 Paket 17,00 kg", "ship via check");
ok ($invoice->shippingpoint eq "Maisenhaus", "shipping point check");
ok ($invoice->ordnumber eq "A16399", "ordnumber check");
ok ($invoice->donumber eq "L20199", "donumber check");
ok(($do1->closed) , 'Delivery Order is closed after conversion');
ok (SL::DB::PaymentTerm->new(id => $invoice->{payment_id})->load->description eq "14Tage 2%Skonto, 30Tage netto", 'payment term description check');
# some test data from original client invoice console (!)
# my $invoice3 = SL::DB::Manager::Invoice->find_by( ordnumber => 'A16399' );
# which will fail due to PTC Calculation differs from GUI-Calculation, see issue: http://redmine.kivitendo-premium.de/issues/82
# pp $invoice3
# values from gui should be:
#ok($invoice->amount == 1354.20000, 'amount check');
#ok($invoice->marge_percent == 50.88666, 'marge percent check');
#ok($invoice->marge_total == 579.08000, 'marge total check');
#ok($invoice->netamount == 1137.98000, 'netamount check');
# the values change if one reloads the object
# without reloading we get this failures
#not ok 17 - amount check
# Failed test 'amount check'
# at t/db_helper/convert_invoice.t line 272.
# got: '1354.17'
# expected: '1354.17000'
#not ok 18 - marge percent check
# Failed test 'marge percent check'
# at t/db_helper/convert_invoice.t line 273.
# got: '50.8857956342929'
# expected: '50.88580'
#not ok 19 - marge total check
# Failed test 'marge total check'
# at t/db_helper/convert_invoice.t line 274.
# got: '579.06'
# expected: '579.06000'
#not ok 20 - netamount check
# Failed test 'netamount check'
# at t/db_helper/convert_invoice.t line 275.
# got: '1137.96'
# expected: '1137.96000'
$invoice->load;
ok($invoice->currency_id eq '1', 'currency_id');
ok($invoice->cusordnumber eq 'b84da', 'cusordnumber check');
ok(SL::DB::Department->new(id => $invoice->{department_id})->load->description eq "Maisenhaus-Versand", 'department description');
is($invoice->amount, '1354.17000', 'amount check');
is($invoice->marge_percent, '50.88580', 'marge percent check');
is($invoice->marge_total, '579.06000', 'marge total check');
is($invoice->netamount, '1137.96000', 'netamount check');
# some item checks
ok(@ {$invoice->items_sorted}[0]->parts_id eq '26321', 'invoiceitem 1 linked with part');
ok(2 == scalar@{ $invoice->invoiceitems }, 'two invoice items linked with invoice');
is(@ {$invoice->items_sorted}[0]->position, 1, "position 1 order correct");
is(@ {$invoice->items_sorted}[1]->position, 2, "position 2 order correct");
is(@ {$invoice->items_sorted}[0]->part->partnumber, 'v-519160549', "partnumber 1 correct");
is(@ {$invoice->items_sorted}[1]->part->partnumber, 'v-120160086', "partnumber 2 correct");
is(@ {$invoice->items_sorted}[0]->qty, '2.00000', "pos 1 qty");
is(@ {$invoice->items_sorted}[1]->qty, '3.00000', "pos 2 qty");
is(@ {$invoice->items_sorted}[0]->discount, 0.25, "pos 1 discount");
is(@ {$invoice->items_sorted}[1]->discount, 0.25, "pos 2 discount");
# more ideas: check onhand, lastcost (parsed lastcost)
clear_up();
1;

Auch abrufbar als: Unified diff