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