088bb087f21d06d522428d31920c03922eeccc2f
[kivitendo-erp.git] / t / db_helper / convert_invoice.t
1 use Test::More tests => 38;
2
3 use strict;
4
5 use lib 't';
6 use utf8;
7
8 use Support::TestSetup;
9
10 use Carp;
11 use Data::Dumper;
12 use Support::TestSetup;
13 use Test::Exception;
14 use List::Util qw(max);
15
16 use SL::DB::Buchungsgruppe;
17 use SL::DB::Currency;
18 use SL::DB::Customer;
19 use SL::DB::Employee;
20 use SL::DB::Invoice;
21 use SL::DB::Order;
22 use SL::DB::DeliveryOrder;
23 use SL::DB::Part;
24 use SL::DB::Unit;
25 use SL::DB::TaxZone;
26
27 my ($customer, $currency_id, $buchungsgruppe, $employee, $vendor, $taxzone, $buchungsgruppe7, $tax, $tax7,
28     $unit, @parts);
29
30 my $VISUAL_TEST = 0;  # just a sleep to click around
31
32 sub clear_up {
33   foreach (qw(DeliveryOrderItem DeliveryOrder InvoiceItem Invoice Part Customer Vendor Employee Department PaymentTerm)) {
34     "SL::DB::Manager::${_}"->delete_all(all => 1);
35   }
36 };
37
38 sub reset_state {
39   my %params = @_;
40
41   clear_up();
42
43   $buchungsgruppe   = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 19%', %{ $params{buchungsgruppe} }) || croak "No accounting group 19\%";
44   $buchungsgruppe7  = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 7%', %{ $params{buchungsgruppe} })  || croak "No accounting group 7\%";
45   $taxzone          = SL::DB::Manager::TaxZone->find_by( description => 'Inland')                                           || croak "No taxzone";
46   $tax              = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19, %{ $params{tax} })                           || croak "No tax for 19\%";
47   $tax7             = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07)                                              || croak "No tax for 7\%";
48   $unit             = SL::DB::Manager::Unit->find_by(name => 'kg', %{ $params{unit} })                                      || croak "No unit";
49   $currency_id     = $::instance_conf->get_currency_id;
50
51   $customer     = SL::DB::Customer->new(
52     name        => '520484567dfaedc9e60fc',
53     currency_id => $currency_id,
54     taxzone_id  => $taxzone->id,
55     %{ $params{customer} }
56   )->save;
57
58   # some od.rnr real anonym data
59   my $employee_bk = SL::DB::Employee->new(
60                 'id' => 31915,
61                 'login' => 'barbuschka.kappes',
62                 'name' => 'Barbuschka Kappes',
63   )->save;
64
65   my $department_do = SL::DB::Department->new(
66                  'description' => 'Maisenhaus-Versand',
67                  'id' => 32149,
68                  'itime' => undef,
69                  'mtime' => undef
70   )->save;
71
72   my $payment_do = SL::DB::PaymentTerm->new(
73                  'description' => '14Tage 2%Skonto, 30Tage netto',
74                  '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.",
75                  'id' => 11276,
76                  'itime' => undef,
77                  'mtime' => undef,
78                  'percent_skonto' => '0.02',
79                  'ranking' => undef,
80                  'sortkey' => 4,
81                  'terms_netto' => 30,
82                  'auto_calculation' => undef,
83                  'terms_skonto' => 14
84   )->save;
85
86   # two real parts
87   @parts = ();
88   push @parts, SL::DB::Part->new(
89                  'id' => 26321,
90                  'image' => '',
91                  'lastcost' => '49.95000',
92                  'listprice' => '0.00000',
93                  'onhand' => '5.00000',
94                  'partnumber' => 'v-519160549',
95                  #'partsgroup_id' => 111645,
96                  'rop' => '0',
97                  'sellprice' => '242.20000',
98                  #'warehouse_id' => 64702,
99                  'weight' => '0.79',
100                  description        => "Nussbaum, Gr.5, Unterfilz weinrot, genietet[[Aufschnittbreite: 11,0, Kernform: US]]\"" ,
101                  buchungsgruppen_id => $buchungsgruppe->id,
102                  unit               => $unit->name,
103                  id                 => 26321,
104   )->save;
105
106   push @parts, SL::DB::Part->new(
107                  'description' => "[[0640]]Flügel Hammerstiele bestehend aus:
108 70 Stielen Standard in Weißbuche und
109 20 Stielen Diskant abgekehlt in Weißbuche
110 mit Röllchen aus Synthetikleder,
111 Kapseln mit Yamaha Profil, Kerbenabstand 3,6 mm mit eingedrehten Abnickschrauben",
112                  'id' => 25505,
113                  'lastcost' => '153.00000',
114                  'listprice' => '0.00000',
115                  'onhand' => '9.00000',
116                  'partnumber' => 'v-120160086',
117                  # 'partsgroup_id' => 111639,
118                  'rop' => '0',
119                  'sellprice' => '344.30000',
120                  'weight' => '0.9',
121                   buchungsgruppen_id => $buchungsgruppe->id,
122                   unit               => $unit->name,
123   )->save;
124 }
125
126 sub new_delivery_order {
127   my %params  = @_;
128
129   return SL::DB::DeliveryOrder->new(
130    currency_id => $currency_id,
131    taxzone_id  => $taxzone->id,
132     %params,
133   )->save;
134 }
135
136 Support::TestSetup::login();
137
138 reset_state();
139
140 # we create L20199 with two items
141 my $do1 = new_delivery_order('department_id'    => 32149,
142                              'donumber'         => 'L20199',
143                              'employee_id'      => 31915,
144                              'intnotes'         => 'Achtung: Neue Lieferadresse ab 16.02.2015 in der Carl-von-Ossietzky-Str.32!   13.02.2015/MH
145
146                                             Steinway-Produkte (201...) immer plus 25% dazu rechnen / BK 13.02.2014',
147                               'ordnumber'       => 'A16399',
148                               'payment_id'      => 11276,
149                               'salesman_id'     => 31915,
150                               'shippingpoint'   => 'Maisenhaus',
151                               # 'shipto_id'     => 451463,
152                               'is_sales'        => 'true',
153                               'shipvia'         => 'DHL, Versand am 06.03.2015, 1 Paket  17,00 kg',
154                               'taxzone_id'      => 4,
155                               'closed'          => undef,
156                               # 'currency_id'   => 1,
157                               'cusordnumber'    => 'b84da',
158                               'customer_id'     => $customer->id,
159                               'id'              => 464003,
160 );
161
162 my $do1_item1 = SL::DB::DeliveryOrderItem->new('delivery_order_id' => 464003,
163                                                'description' => "Flügel Hammerkopf bestehend aus:
164                                                                  Bass/Diskant 26/65 Stück, Gesamtlänge 80/72, Bohrlänge 56/48
165                                                                  Nussbaum, Gr.5, Unterfilz weinrot, genietet[[Aufschnittbreite: 11,0, Kernform: US]]",
166                                                'discount' => '0.25',
167                                                'id' => 144736,
168                                                'lastcost' => '49.95000',
169                                                'longdescription' => '',
170                                                'marge_price_factor' => 1,
171                                                'mtime' => undef,
172                                                'ordnumber' => 'A16399',
173                                                'parts_id' => 26321,
174                                                'position' => 1,
175                                                'price_factor' => 1,
176                                                'qty' => '2.00000',
177                                                'sellprice' => '242.20000',
178                                                'transdate' => '06.03.2015',
179                                                'unit' => 'kg')->save;
180
181 my $do1_item2 = SL::DB::DeliveryOrderItem->new('delivery_order_id' => 464003,
182                  'description' => "[[0640]]Flügel Hammerstiele bestehend aus:
183 70 Stielen Standard in Weißbuche und
184 20 Stielen Diskant abgekehlt in Weißbuche
185 mit Röllchen aus Synthetikleder,
186 Kapseln mit Yamaha Profil, Kerbenabstand 3,6 mm mit eingedrehten Abnickschrauben",
187                  'discount' => '0.25',
188                  'id' => 144737,
189                  'itime' => undef,
190                  'lastcost' => '153.00000',
191                  'longdescription' => '',
192                  'marge_price_factor' => 1,
193                  'mtime' => undef,
194                  'ordnumber' => 'A16399',
195                  'parts_id' => 25505,
196                  'position' => 2,
197                  'price_factor' => 1,
198                  'price_factor_id' => undef,
199                  'pricegroup_id' => undef,
200                  'project_id' => undef,
201                  'qty' => '3.00000',
202                  'reqdate' => undef,
203                  'sellprice' => '344.30000',
204                  'serialnumber' => '',
205                  'transdate' => '06.03.2015',
206                  'unit' => 'kg')->save;
207
208 # TESTS
209
210
211 # test delivery order before any conversion
212 ok($do1->donumber eq "L20199", 'Delivery Order Number created');
213 ok((not $do1->closed) , 'Delivery Order is not closed');
214 ok($do1_item1->parts_id eq '26321', 'doi linked with part');
215 ok($do1_item1->qty == 2, 'qty check doi');
216 ok($do1_item2->position == 2, 'doi2 position check');
217 ok(2 ==  scalar@{ SL::DB::Manager::DeliveryOrderItem->get_all(where => [ delivery_order_id => $do1->id ]) }, 'two doi linked');
218
219
220 # convert this do to invoice
221 my $invoice = $do1->convert_to_invoice();
222
223 sleep (300) if $VISUAL_TEST; # we can do a real visual test via gui login
224 # test invoice afterwards
225
226 ok ($invoice->shipvia eq "DHL, Versand am 06.03.2015, 1 Paket  17,00 kg", "ship via check");
227 ok ($invoice->shippingpoint eq "Maisenhaus", "shipping point check");
228 ok ($invoice->ordnumber eq "A16399", "ordnumber check");
229 ok ($invoice->donumber eq "L20199", "donumber check");
230 ok(($do1->closed) , 'Delivery Order is closed after conversion');
231 ok (SL::DB::PaymentTerm->new(id => $invoice->{payment_id})->load->description eq "14Tage 2%Skonto, 30Tage netto", 'payment term description check');
232
233 # some test data from original client invoice console (!)
234 # my $invoice3 = SL::DB::Manager::Invoice->find_by( ordnumber => 'A16399' );
235 # which will fail due to PTC Calculation differs from GUI-Calculation, see issue: http://redmine.kivitendo-premium.de/issues/82
236 # pp $invoice3
237 # values from gui should be:
238 #ok($invoice->amount == 1354.20000, 'amount check');
239 #ok($invoice->marge_percent == 50.88666, 'marge percent check');
240 #ok($invoice->marge_total == 579.08000, 'marge total check');
241 #ok($invoice->netamount == 1137.98000, 'netamount check');
242
243
244 # the values change if one reloads the object
245 # without reloading we get this failures
246 #not ok 17 - amount check
247 #   Failed test 'amount check'
248 #   at t/db_helper/convert_invoice.t line 272.
249 #          got: '1354.17'
250 #     expected: '1354.17000'
251 #not ok 18 - marge percent check
252 #   Failed test 'marge percent check'
253 #   at t/db_helper/convert_invoice.t line 273.
254 #          got: '50.8857956342929'
255 #     expected: '50.88580'
256 #not ok 19 - marge total check
257 #   Failed test 'marge total check'
258 #   at t/db_helper/convert_invoice.t line 274.
259 #          got: '579.06'
260 #     expected: '579.06000'
261 #not ok 20 - netamount check
262 #   Failed test 'netamount check'
263 #   at t/db_helper/convert_invoice.t line 275.
264 #          got: '1137.96'
265 #     expected: '1137.96000'
266
267 $invoice->load;
268
269 ok($invoice->currency_id eq '1', 'currency_id');
270 ok($invoice->cusordnumber eq 'b84da', 'cusordnumber check');
271 ok(SL::DB::Department->new(id => $invoice->{department_id})->load->description eq "Maisenhaus-Versand", 'department description');
272 is($invoice->amount, '1354.17000', 'amount check');
273 is($invoice->marge_percent, '50.88580', 'marge percent check');
274 is($invoice->marge_total, '579.06000', 'marge total check');
275 is($invoice->netamount, '1137.96000', 'netamount check');
276
277 # some item checks
278 ok(@ {$invoice->items_sorted}[0]->parts_id eq '26321', 'invoiceitem 1 linked with part');
279 ok(2 ==  scalar@{ $invoice->invoiceitems }, 'two invoice items linked with invoice');
280 is(@ {$invoice->items_sorted}[0]->position, 1, "position 1 order correct");
281 is(@ {$invoice->items_sorted}[1]->position, 2, "position 2 order correct");
282 is(@ {$invoice->items_sorted}[0]->part->partnumber, 'v-519160549', "partnumber 1 correct");
283 is(@ {$invoice->items_sorted}[1]->part->partnumber, 'v-120160086', "partnumber 2 correct");
284 is(@ {$invoice->items_sorted}[0]->qty, '2.00000', "pos 1 qty");
285 is(@ {$invoice->items_sorted}[1]->qty, '3.00000', "pos 2 qty");
286 is(@ {$invoice->items_sorted}[0]->discount, 0.25, "pos 1 discount");
287 is(@ {$invoice->items_sorted}[1]->discount, 0.25, "pos 2 discount");
288
289 # more ideas: check onhand, lastcost (parsed lastcost)
290
291
292
293 # check linked records AND linked items
294
295 # we expect something like this in record links:
296 # delivery_order_items |  144736 | invoice  |     9 | 2015-09-02 16:29:32.362562 |  5
297 # delivery_order_items |  144737 | invoice  |    10 | 2015-09-02 16:29:32.362562 |  6
298 # delivery_orders      |  464003 | ar       |     5 | 2015-09-02 16:29:32.362562 |  7
299 # wir erwarten:
300 # verkn�pfter beleg$VAR1 = {
301 #           'from_id' => 464003,
302 #           'from_table' => 'delivery_orders',
303 #           'to_id' => 11,
304 #           'to_table' => 'ar'
305 #         };
306 # verkn�pfte positionen$VAR1 = {
307 #           'from_id' => 144737,
308 #           'from_table' => 'delivery_order_items',
309 #           'to_id' => 22,
310 #           'to_table' => 'invoice'
311 #         };
312 # $VAR2 = {
313 #           'from_id' => 144736,
314 #           'from_table' => 'delivery_order_items',
315 #           'to_id' => 21,
316 #           'to_table' => 'invoice'
317 #         };
318
319
320
321 my @links_record    = RecordLinks->get_links('from_table' => 'delivery_orders',
322                                              'to_table'   => 'ar',
323                                              'from_id'      => 464003);
324 is($links_record[0]->{from_id}, '464003', "record from id check");
325 is($links_record[0]->{from_table}, 'delivery_orders', "record from table check");
326 is($links_record[0]->{to_table}, 'ar', "record to table check");
327
328 foreach (qw(144736 144737)) {
329   my @links_record_item1 = RecordLinks->get_links('from_table' => 'delivery_order_items',
330                                                  'to_table'   => 'invoice',
331                                                  'from_id'      => $_);
332   is($links_record_item1[0]->{from_id}, $_, "record from id check $_");
333   is($links_record_item1[0]->{from_table}, 'delivery_order_items', "record from table check $_");
334   is($links_record_item1[0]->{to_table}, 'invoice', "record to table check $_");
335 }
336
337
338 clear_up();
339
340 1;