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