5c2c8613061729675779886c46ac549e11859a22
[koha.git] / t / Prices.t
1 use Modern::Perl;
2 use Test::More;
3 use Test::MockModule;
4
5 use t::lib::Mocks;
6
7 use Module::Load::Conditional qw/check_install/;
8
9 BEGIN {
10     if ( check_install( module => 'Test::DBIx::Class' ) ) {
11         plan tests => 16;
12     } else {
13         plan skip_all => "Need Test::DBIx::Class"
14     }
15 }
16
17 use_ok('C4::Acquisition');
18 use_ok('C4::Context');
19 use_ok('Koha::Number::Price');
20
21 t::lib::Mocks::mock_preference( 'TaxRates', '0.02|0.05|0.196' );
22
23 use Test::DBIx::Class;
24
25 my $db = Test::MockModule->new('Koha::Database');
26 $db->mock( _new_schema => sub { return Schema(); } );
27 Koha::Database::flush_schema_cache();
28
29 fixtures_ok [
30     Currency => [
31         [ qw/ currency symbol rate active / ],
32         [ 'my_cur', '€', 1, 1, ],
33     ],
34     Aqbookseller => [
35         [ qw/ id name listincgst invoiceincgst / ],
36         [ 1, '0 0', 0, 0 ],
37         [ 2, '0 1', 0, 1 ],
38         [ 3, '1 0', 1, 0 ],
39         [ 4, '1 1', 1, 1 ],
40     ],
41 ], 'add currency fixtures';
42
43 my $bookseller_module = Test::MockModule->new('Koha::Acquisition::Bookseller');
44
45 my ( $basketno_0_0,  $basketno_1_1 );
46 my ( $invoiceid_0_0, $invoiceid_1_1 );
47 my $today;
48
49 for my $currency_format ( qw( US FR ) ) {
50     t::lib::Mocks::mock_preference( 'CurrencyFormat', $currency_format );
51     subtest 'Configuration 1: 0 0 (Vendor List prices do not include tax / Invoice prices do not include tax)' => sub {
52         plan tests => 8;
53
54         my $biblionumber_0_0 = 42;
55
56         my $order_0_0 = {
57             biblionumber     => $biblionumber_0_0,
58             quantity         => 2,
59             listprice        => 82,
60             unitprice        => 73.80,
61             quantityreceived => 2,
62             basketno         => $basketno_0_0,
63             invoiceid        => $invoiceid_0_0,
64             rrp              => 82.00,
65             ecost            => 73.80,
66             tax_rate         => 0.0500,
67             discount         => 10,
68             datereceived     => $today
69         };
70         $order_0_0 = C4::Acquisition::populate_order_with_prices(
71             {
72                 order        => $order_0_0,
73                 booksellerid => 1,
74                 ordering     => 1,
75             }
76         );
77
78         compare(
79             {
80                 got      => $order_0_0->{rrp_tax_included},
81                 expected => 86.10,
82                 conf     => '0 0',
83                 field    => 'rrp_tax_included'
84             }
85         );
86         compare(
87             {
88                 got      => $order_0_0->{rrp_tax_excluded},
89                 expected => 82.00,
90                 conf     => '0 0',
91                 field    => 'rrp_tax_excluded'
92             }
93         );
94         compare(
95             {
96                 got      => $order_0_0->{ecost_tax_included},
97                 expected => 77.49,
98                 conf     => '0 0',
99                 field    => 'ecost_tax_included'
100             }
101         );
102         compare(
103             {
104                 got      => $order_0_0->{ecost_tax_excluded},
105                 expected => 73.80,
106                 conf     => '0 0',
107                 field    => 'ecost_tax_excluded'
108             }
109         );
110         compare(
111             {
112                 got      => $order_0_0->{tax_value_on_ordering},
113                 expected => 7.38,
114                 conf     => '0 0',
115                 field    => 'tax_value'
116             }
117         );
118
119         $order_0_0 = C4::Acquisition::populate_order_with_prices(
120             {
121                 order        => $order_0_0,
122                 booksellerid => 1,
123                 receiving    => 1,
124             }
125         );
126
127         compare(
128             {
129                 got      => $order_0_0->{unitprice_tax_included},
130                 expected => 77.49,
131                 conf     => '0 0',
132                 field    => 'unitprice_tax_included'
133             }
134         );
135         compare(
136             {
137                 got      => $order_0_0->{unitprice_tax_excluded},
138                 expected => 73.80,
139                 conf     => '0 0',
140                 field    => 'unitprice_tax_excluded'
141             }
142         );
143         compare(
144             {
145                 got      => $order_0_0->{tax_value_on_receiving},
146                 expected => 7.38,
147                 conf     => '0 0',
148                 field    => 'tax_value'
149             }
150         );
151     };
152
153     subtest 'Configuration 1: 1 1 (Vendor List prices do include tax / Invoice prices include tax)' => sub {
154         plan tests => 11;
155
156         my $biblionumber_1_1 = 43;
157         my $order_1_1        = {
158             biblionumber     => $biblionumber_1_1,
159             quantity         => 2,
160             listprice        => 82,
161             unitprice        => 73.80,
162             quantityreceived => 2,
163             basketno         => $basketno_1_1,
164             invoiceid        => $invoiceid_1_1,
165             rrp              => 82.00,
166             ecost            => 73.80,
167             tax_rate         => 0.0500,
168             discount         => 10,
169             datereceived     => $today
170         };
171
172         $order_1_1 = C4::Acquisition::populate_order_with_prices(
173             {
174                 order        => $order_1_1,
175                 booksellerid => 4,
176                 ordering     => 1,
177             }
178         );
179
180         compare(
181             {
182                 got      => $order_1_1->{rrp_tax_included},
183                 expected => 82.00,
184                 conf     => '1 1',
185                 field    => 'rrp_tax_included'
186             }
187         );
188         compare(
189             {
190                 got      => $order_1_1->{rrp_tax_excluded},
191                 expected => 78.10,
192                 conf     => '1 1',
193                 field    => 'rrp_tax_excluded'
194             }
195         );
196         compare(
197             {
198                 got      => $order_1_1->{ecost_tax_included},
199                 expected => 73.80,
200                 conf     => '1 1',
201                 field    => 'ecost_tax_included'
202             }
203         );
204         compare(
205             {
206                 got      => $order_1_1->{ecost_tax_excluded},
207                 expected => 70.29,
208                 conf     => '1 1',
209                 field    => 'ecost_tax_excluded'
210             }
211         );
212         compare(
213             {
214                 got      => $order_1_1->{tax_value_on_ordering},
215                 expected => 7.03,
216                 conf     => '1 1',
217                 field    => 'tax_value'
218             }
219         );
220
221         $order_1_1 = C4::Acquisition::populate_order_with_prices(
222             {
223                 order        => $order_1_1,
224                 booksellerid => 4,
225                 receiving    => 1,
226             }
227         );
228
229         compare(
230             {
231                 got      => $order_1_1->{unitprice_tax_included},
232                 expected => 73.80,
233                 conf     => '1 1',
234                 field    => 'unitprice_tax_included'
235             }
236         );
237         compare(
238             {
239                 got      => $order_1_1->{unitprice_tax_excluded},
240                 expected => 70.29,
241                 conf     => '1 1',
242                 field    => 'unitprice_tax_excluded'
243             }
244         );
245         compare(
246             {
247                 got      => $order_1_1->{tax_value_on_receiving},
248                 expected => 7.03,
249                 conf     => '1 1',
250                 field    => 'tax_value'
251             }
252         );
253
254         # When unitprice is 0.00 C4::Acquisition->populate_order_with_prices() falls back to using ecost_tax_included and ecost_tax_excluded
255         $order_1_1        = {
256             biblionumber     => $biblionumber_1_1,
257             quantity         => 1,
258             listprice        => 10,
259             unitprice        => '0.00',
260             quantityreceived => 1,
261             basketno         => $basketno_1_1,
262             invoiceid        => $invoiceid_1_1,
263             rrp              => 10.00,
264             ecost            => 10.00,
265             tax_rate         => 0.1500,
266             discount         => 0,
267             datereceived     => $today
268         };
269
270         $order_1_1 = C4::Acquisition::populate_order_with_prices(
271             {
272                 order        => $order_1_1,
273                 booksellerid => 4,
274                 ordering     => 1,
275             }
276         );
277
278         compare(
279             {
280                 got      => $order_1_1->{ecost_tax_included},
281                 expected => 10.00,
282                 conf     => '1 1',
283                 field    => 'ecost_tax_included'
284             }
285         );
286         compare(
287             {
288                 got      => $order_1_1->{ecost_tax_excluded},
289                 expected => 8.70,
290                 conf     => '1 1',
291                 field    => 'ecost_tax_excluded'
292             }
293         );
294         compare(
295             {
296                 got      => $order_1_1->{tax_value_on_ordering},
297                 expected => 1.30,
298                 conf     => '1 1',
299                 field    => 'tax_value'
300             }
301         );
302     };
303
304     subtest 'Configuration 1: 1 0 (Vendor List prices include tax / Invoice prices do not include tax)' => sub {
305         plan tests => 9;
306
307         my $biblionumber_1_0 = 44;
308         my $order_1_0        = {
309             biblionumber     => $biblionumber_1_0,
310             quantity         => 2,
311             listprice        => 82,
312             unitprice        => 0,
313             quantityreceived => 2,
314             basketno         => $basketno_1_1,
315             invoiceid        => $invoiceid_1_1,
316             rrp              => 82.00,
317             ecost            => 73.80,
318             tax_rate         => 0.0500,
319             discount         => 10,
320             datereceived     => $today
321         };
322
323         $order_1_0 = C4::Acquisition::populate_order_with_prices(
324             {
325                 order        => $order_1_0,
326                 booksellerid => 3,
327                 ordering     => 1,
328             }
329         );
330
331         compare(
332             {
333                 got      => $order_1_0->{rrp_tax_included},
334                 expected => 82,
335                 conf     => '1 0',
336                 field    => 'rrp_tax_included'
337             }
338         );
339         compare(
340             {
341                 got      => $order_1_0->{rrp_tax_excluded},
342                 expected => 78.10,
343                 conf     => '1 0',
344                 field    => 'rrp_tax_excluded'
345             }
346         );
347         compare(
348             {
349                 got      => $order_1_0->{ecost_tax_included},
350                 expected => 73.80,
351                 conf     => '1 0',
352                 field    => 'ecost_tax_included'
353             }
354         );
355         compare(
356             {
357                 got      => $order_1_0->{ecost_tax_excluded},
358                 expected => 70.29,
359                 conf     => '1 0',
360                 field    => 'ecost_tax_excluded'
361             }
362         );
363         # If we order with unitprice = 0, tax is calculated from the ecost
364         # (note that in addorder.pl and addorderiso2709 the unitprice may/will be set to the ecost
365         compare(
366             {
367                 got      => $order_1_0->{tax_value_on_ordering},
368                 expected => 7.03,
369                 conf     => '1 0',
370                 field    => 'tax_value'
371             }
372         );
373         $order_1_0->{unitprice} = 70.29;
374         $order_1_0 = C4::Acquisition::populate_order_with_prices(
375             {
376                 order        => $order_1_0,
377                 booksellerid => 3,
378                 ordering    => 1,
379             }
380         );
381         # If a unitprice is provided at ordering, we calculate the tax from that
382         compare(
383             {
384                 got      => $order_1_0->{tax_value_on_ordering},
385                 expected => 6.69,
386                 conf     => '1 0',
387                 field    => 'tax_value'
388             }
389         );
390
391         $order_1_0 = C4::Acquisition::populate_order_with_prices(
392             {
393                 order        => $order_1_0,
394                 booksellerid => 3,
395                 receiving    => 1,
396             }
397         );
398
399         compare(
400             {
401                 got      => $order_1_0->{unitprice_tax_included},
402                 expected => 73.80,
403                 conf     => '1 0',
404                 field    => 'unitprice_tax_included'
405             }
406         );
407         compare(
408             {
409                 got      => $order_1_0->{unitprice_tax_excluded},
410                 expected => 70.29,
411                 conf     => '1 0',
412                 field    => 'unitprice_tax_excluded'
413             }
414         );
415         compare(
416             {
417                 got      => $order_1_0->{tax_value_on_receiving},
418                 expected => 7.03,
419                 conf     => '1 0',
420                 field    => 'tax_value'
421             }
422         );
423     };
424
425     subtest 'Configuration 1: 0 1 (Vendor List prices do not include tax / Invoice prices include tax)' => sub {
426         plan tests => 9;
427
428         my $biblionumber_0_1 = 45;
429         my $order_0_1        = {
430             biblionumber     => $biblionumber_0_1,
431             quantity         => 2,
432             listprice        => 82,
433             unitprice        => 0,
434             quantityreceived => 2,
435             basketno         => $basketno_1_1,
436             invoiceid        => $invoiceid_1_1,
437             rrp              => 82.00,
438             ecost            => 73.80,
439             tax_rate         => 0.0500,
440             discount         => 10,
441             datereceived     => $today
442         };
443
444         $order_0_1 = C4::Acquisition::populate_order_with_prices(
445             {
446                 order        => $order_0_1,
447                 booksellerid => 2,
448                 ordering     => 1,
449             }
450         );
451
452         compare(
453             {
454                 got      => $order_0_1->{rrp_tax_included},
455                 expected => 86.10,
456                 conf     => '0 1',
457                 field    => 'rrp_tax_included'
458             }
459         );
460         compare(
461             {
462                 got      => $order_0_1->{rrp_tax_excluded},
463                 expected => 82.00,
464                 conf     => '0 1',
465                 field    => 'rrp_tax_excluded'
466             }
467         );
468         compare(
469             {
470                 got      => $order_0_1->{ecost_tax_included},
471                 expected => 77.49,
472                 conf     => '0 1',
473                 field    => 'ecost_tax_included'
474             }
475         );
476         compare(
477             {
478                 got      => $order_0_1->{ecost_tax_excluded},
479                 expected => 73.80,
480                 conf     => '0 1',
481                 field    => 'ecost_tax_excluded'
482             }
483         );
484         # If we order with unitprice = 0, tax is calculated from the ecost
485         # (note that in addorder.pl and addorderiso2709 the unitprice may/will be set to the ecost
486         compare(
487             {
488                 got      => $order_0_1->{tax_value_on_ordering},
489                 expected => 7.38,
490                 conf     => '0 1',
491                 field    => 'tax_value'
492             }
493         );
494         $order_0_1->{unitprice} = 77.490000;
495         $order_0_1 = C4::Acquisition::populate_order_with_prices(
496             {
497                 order        => $order_0_1,
498                 booksellerid => 2,
499                 ordering     => 1,
500             }
501         );
502         # If a unitprice is provided at ordering, we calculate the tax from that
503         compare(
504             {
505                 got      => $order_0_1->{tax_value_on_ordering},
506                 expected => 7.75,
507                 conf     => '0 1',
508                 field    => 'tax_value'
509             }
510         );
511         $order_0_1 = C4::Acquisition::populate_order_with_prices(
512             {
513                 order        => $order_0_1,
514                 booksellerid => 2,
515                 receiving    => 1,
516             }
517         );
518
519         compare(
520             {
521                 got      => $order_0_1->{unitprice_tax_included},
522                 expected => 77.49,
523                 conf     => '0 1',
524                 field    => 'unitprice_tax_included'
525             }
526         );
527         compare(
528             {
529                 got      => $order_0_1->{unitprice_tax_excluded},
530                 expected => 73.80,
531                 conf     => '0 1',
532                 field    => 'unitprice_tax_excluded'
533             }
534         );
535         compare(
536             {
537                 got      => $order_0_1->{tax_value_on_receiving},
538                 expected => 7.38,
539                 conf     => '0 1',
540                 field    => 'tax_value'
541             }
542         );
543     };
544
545 }
546
547 sub compare {
548     my ($params) = @_;
549     is(
550         Koha::Number::Price->new( $params->{got} )->format,
551         Koha::Number::Price->new( $params->{expected} )->format,
552 "configuration $params->{conf}: $params->{field} should be correctly calculated"
553     );
554 }
555
556 # format_for_editing
557 for my $currency_format ( qw( US FR ) ) {
558     t::lib::Mocks::mock_preference( 'CurrencyFormat', $currency_format );
559     is( Koha::Number::Price->new( 1234567 )->format_for_editing, '1234567.00', 'format_for_editing should return unformated integer part with 2 decimals' );
560     is( Koha::Number::Price->new( 1234567.89 )->format_for_editing, '1234567.89', 'format_for_editing should return unformated integer part with 2 decimals' );
561 }