Zeiterfassung: Konvertierung: Refoctored -> zentrale Prüfung der Parameter
[kivitendo-erp.git] / t / background_job / convert_time_recordings.t
1 use Test::More tests => 34;
2
3 use strict;
4
5 use lib 't';
6 use utf8;
7
8 use Support::TestSetup;
9 use Test::Exception;
10 use DateTime;
11 use Rose::DB::Object::Helpers qw(forget_related);
12
13 use SL::DB::BackgroundJob;
14 use SL::DB::DeliveryOrder;
15
16 use_ok 'SL::BackgroundJob::ConvertTimeRecordings';
17
18 use SL::Dev::ALL qw(:ALL);
19
20 Support::TestSetup::login();
21
22 sub clear_up {
23   foreach (qw(TimeRecording OrderItem Order DeliveryOrder Project Part Customer RecordLink)) {
24     "SL::DB::Manager::${_}"->delete_all(all => 1);
25   }
26   SL::DB::Manager::Employee->delete_all(where => [ '!login' => 'unittests' ]);
27 };
28
29 ########################################
30
31 $::myconfig{numberformat} = '1000.00';
32 my $old_locale = $::locale;
33 # set locale to en so we can match errors
34 $::locale = Locale->new('en');
35
36
37 clear_up();
38
39 ########################################
40 # two time recordings, one order linked with project_id
41 ########################################
42 my $part     = new_service(partnumber => 'Serv1', unit => 'Std')->save;
43 my $project  = create_project(projectnumber => 'p1', description => 'Project 1');
44 my $customer = new_customer()->save;
45
46 # sales order with globalproject_id
47 my $sales_order = create_sales_order(
48   save             => 1,
49   customer         => $customer,
50   globalproject    => $project,
51   taxincluded      => 0,
52   orderitems       => [ create_order_item(part => $part, qty => 3, sellprice => 70), ]
53 );
54
55 my @time_recordings;
56 push @time_recordings, new_time_recording(
57   start_time => DateTime->new(year => 2021, month =>  4, day => 19, hour => 10, minute =>  5),
58   end_time   => DateTime->new(year => 2021, month =>  4, day => 19, hour => 11, minute =>  5),
59   customer   => $customer,
60   project    => $project,
61   part       => $part,
62 )->save;
63 push @time_recordings, new_time_recording(
64   start_time => DateTime->new(year => 2021, month =>  4, day => 19, hour => 12, minute =>  5),
65   end_time   => DateTime->new(year => 2021, month =>  4, day => 19, hour => 14, minute =>  5),
66   customer   => $customer,
67   project    => $project,
68   part       => $part,
69 )->save;
70
71 my %data   = (
72   link_order => 1,
73   project_id => $project->id,
74   from_date  => '01.01.2021',
75   to_date    => '30.04.2021',
76 );
77 my $db_obj = SL::DB::BackgroundJob->new();
78 $db_obj->set_data(%data);
79 my $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
80 my $ret    = $job->run($db_obj);
81
82 is_deeply($job->{job_errors}, [], 'no errros');
83 like($ret, qr{^Number of delivery orders created: 1}, 'one delivery order created');
84
85 my $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
86 is(scalar @$linked_dos, 1, 'one delivery order linked to order');
87 is($linked_dos->[0]->globalproject_id, $sales_order->globalproject_id, 'project ids match');
88
89 my $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
90 is(scalar @$linked_items, 1, 'one delivery order item linked to order item');
91 is($linked_items->[0]->qty*1, 3, 'qty in delivery order');
92 is($linked_items->[0]->base_qty*1, 3, 'base_qty in delivery order');
93
94 # reload order and orderitems to get changes to deliverd and ship
95 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
96 $sales_order->load;
97
98 ok($sales_order->delivered, 'related order is delivered');
99 is($sales_order->items->[0]->ship*1, 3, 'ship in related order');
100
101 clear_up();
102
103
104 ########################################
105 # two time recordings, one order linked with project_id
106 # unit in order is 'min', but part is 'Std'
107 ########################################
108 $part     = new_service(partnumber => 'Serv1', unit => 'Std')->save;
109 $project  = create_project(projectnumber => 'p1', description => 'Project 1');
110 $customer = new_customer()->save;
111
112 $sales_order = create_sales_order(
113   save             => 1,
114   customer         => $customer,
115   globalproject    => $project,
116   taxincluded      => 0,
117   orderitems       => [ create_order_item(part => $part, qty => 180, unit => 'min', sellprice => 70), ]
118 );
119
120 @time_recordings = ();
121 push @time_recordings, new_time_recording(
122   start_time => DateTime->new(year => 2021, month =>  4, day => 19, hour => 10, minute => 10),
123   end_time   => DateTime->new(year => 2021, month =>  4, day => 19, hour => 11, minute => 10),
124   customer   => $customer,
125   project    => $project,
126   part       => $part,
127 )->save;
128 push @time_recordings, new_time_recording(
129   start_time => DateTime->new(year => 2021, month =>  4, day => 19, hour => 12, minute => 10),
130   end_time   => DateTime->new(year => 2021, month =>  4, day => 19, hour => 14, minute => 10),
131   customer   => $customer,
132   project    => $project,
133   part       => $part,
134 )->save;
135
136 # two time recordings, one order linked with project_id
137 %data = (
138   link_order => 1,
139   project_id => $project->id,
140   from_date  => '01.04.2021',
141   to_date    => '30.04.2021',
142 );
143 $db_obj = SL::DB::BackgroundJob->new();
144 $db_obj->set_data(%data);
145 $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
146 $ret    = $job->run($db_obj);
147
148 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
149 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
150 is($linked_items->[0]->qty*1, 3, 'different units: qty in delivery order');
151 is($linked_items->[0]->base_qty*1, 3, 'different units: base_qty in delivery order');
152
153 # reload order and orderitems to get changes to deliverd and ship
154 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
155 $sales_order->load;
156
157 ok($sales_order->delivered, 'different units: related order is delivered');
158 is($sales_order->items->[0]->ship*1, 180, 'different units: ship in related order');
159
160 clear_up();
161
162
163 ########################################
164 # two time recordings, one order linked with project_id
165 # unit in order is 'Std', but part is 'min'
166 ########################################
167 $part     = new_service(partnumber => 'Serv1', unit => 'min')->save;
168 $project  = create_project(projectnumber => 'p1', description => 'Project 1');
169 $customer = new_customer()->save;
170
171 $sales_order = create_sales_order(
172   save             => 1,
173   customer         => $customer,
174   globalproject    => $project,
175   taxincluded      => 0,
176   orderitems       => [ create_order_item(part => $part, qty => 2, unit => 'Std', sellprice => 70), ]
177 );
178
179 @time_recordings = ();
180 push @time_recordings, new_time_recording(
181   start_time => DateTime->new(year => 2021, month =>  4, day => 19, hour => 10, minute => 10),
182   end_time   => DateTime->new(year => 2021, month =>  4, day => 19, hour => 11, minute => 10),
183   customer   => $customer,
184   project    => $project,
185   part       => $part,
186 )->save;
187 push @time_recordings, new_time_recording(
188   start_time => DateTime->new(year => 2021, month =>  4, day => 19, hour => 12, minute => 10),
189   end_time   => DateTime->new(year => 2021, month =>  4, day => 19, hour => 13, minute => 10),
190   customer   => $customer,
191   project    => $project,
192   part       => $part,
193 )->save;
194
195 # two time recordings, one order linked with project_id
196 %data = (
197   link_order => 1,
198   project_id => $project->id,
199   from_date  => '01.04.2021',
200   to_date    => '30.04.2021',
201 );
202 $db_obj = SL::DB::BackgroundJob->new();
203 $db_obj->set_data(%data);
204 $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
205 $ret    = $job->run($db_obj);
206
207 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
208 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
209 is($linked_items->[0]->qty*1, 2, 'different units 2: qty in delivery order');
210 is($linked_items->[0]->base_qty*1, 120, 'different units 2: base_qty in delivery order');
211
212 # reload order and orderitems to get changes to deliverd and ship
213 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
214 $sales_order->load;
215
216 ok($sales_order->delivered, 'different units 2: related order is delivered');
217 is($sales_order->items->[0]->ship*1, 2, 'different units 2: ship in related order');
218
219 clear_up();
220
221
222 ########################################
223 # two time recordings, one with start/end one with date/duration
224 ########################################
225 $part     = new_service(partnumber => 'Serv1', unit => 'min')->save;
226 $customer = new_customer()->save;
227
228 @time_recordings = ();
229 push @time_recordings, new_time_recording(
230   start_time => DateTime->new(year => 2021, month =>  4, day => 19, hour => 10, minute => 10),
231   end_time   => DateTime->new(year => 2021, month =>  4, day => 19, hour => 11, minute => 10),
232   customer   => $customer,
233   part       => $part,
234 )->save;
235
236 push @time_recordings, new_time_recording(
237   date       => DateTime->new(year => 2021, month =>  4, day => 19),
238   duration   => 120,
239   start_time => undef,
240   end_time   => undef,
241   customer   => $customer,
242   part       => $part,
243 )->save;
244
245 %data = (
246   link_order => 0,
247   from_date  => '01.04.2021',
248   to_date    => '30.04.2021',
249 );
250 $db_obj = SL::DB::BackgroundJob->new();
251 $db_obj->set_data(%data);
252 $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
253 $ret    = $job->run($db_obj);
254
255 my $dos = SL::DB::Manager::DeliveryOrder->get_all(where => [customer_id => $customer->id]);
256 is($dos->[0]->items->[0]->qty*1, 180/60, 'date/duration and start/end: qty in delivery order');
257 is($dos->[0]->items->[0]->base_qty*1, 180, 'date/duration and start/end2: base_qty in delivery order');
258
259 clear_up();
260
261
262 ########################################
263 # time recording, linked with order_id
264 ########################################
265 $part     = new_service(partnumber => 'Serv1', unit => 'Std')->save;
266 $customer = new_customer()->save;
267
268 # sales order with globalproject_id
269 $sales_order = create_sales_order(
270   save             => 1,
271   customer         => $customer,
272   taxincluded      => 0,
273   orderitems       => [ create_order_item(part => $part, qty => 3, sellprice => 70), ]
274 );
275
276 @time_recordings = ();
277 push @time_recordings, new_time_recording(
278   start_time => DateTime->new(year => 2021, month =>  4, day => 19, hour => 10, minute =>  5),
279   end_time   => DateTime->new(year => 2021, month =>  4, day => 19, hour => 11, minute =>  5),
280   customer   => $customer,
281   order      => $sales_order,
282   part       => $part,
283 )->save;
284
285 %data = (
286   link_order      => 1,
287   from_date       => '01.04.2021',
288   to_date         => '30.04.2021',
289   customernumbers => [$customer->number],
290 );
291 $db_obj = SL::DB::BackgroundJob->new();
292 $db_obj->set_data(%data);
293 $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
294 $ret    = $job->run($db_obj);
295
296 is_deeply($job->{job_errors}, [], 'no errros');
297 like($ret, qr{^Number of delivery orders created: 1}, 'linked by order_id: one delivery order created');
298
299 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
300 is(scalar @$linked_dos, 1, 'linked by order_id: one delivery order linked to order');
301
302 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
303 is(scalar @$linked_items, 1, 'linked by order_id: one delivery order item linked to order item');
304 is($linked_items->[0]->qty*1, 1, 'linked by order_id: qty in delivery order');
305 is($linked_items->[0]->base_qty*1, 1, 'linked by order_id: base_qty in delivery order');
306
307 # reload order and orderitems to get changes to deliverd and ship
308 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
309 $sales_order->load;
310
311 is($sales_order->items->[0]->ship*1, 1, 'linked by order_id: ship in related order');
312
313 clear_up();
314
315
316 ########################################
317 # are wrong params detected?
318 ########################################
319 %data = (
320   from_date       => 'x01.04.2021',
321 );
322 $db_obj = SL::DB::BackgroundJob->new();
323 $db_obj->set_data(%data);
324 $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
325
326 my $err_msg = '';
327 eval { $ret = $job->run($db_obj);  1; } or do {$err_msg = $@};
328 ok($err_msg =~ '^Cannot convert date from string', 'wrong date string detected');
329
330 #####
331
332 $customer = new_customer()->save;
333 %data = (
334   customernumbers => ['a fantasy', $customer->number],
335 );
336
337 $db_obj = SL::DB::BackgroundJob->new();
338 $db_obj->set_data(%data);
339 $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
340
341 $err_msg = '';
342 eval { $ret = $job->run($db_obj);  1; } or do {$err_msg = $@};
343 ok($err_msg =~ '^Not all customer numbers are valid', 'wrong customer number detected');
344
345 #####
346
347 %data = (
348   customernumbers => '123',
349 );
350
351 $db_obj = SL::DB::BackgroundJob->new();
352 $db_obj->set_data(%data);
353 $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
354
355 $err_msg = '';
356 eval { $ret = $job->run($db_obj);  1; } or do {$err_msg = $@};
357 ok($err_msg =~ '^Customer numbers must be given in an array', 'wrong customer number data type detected');
358
359 #####
360
361 %data = (
362   part_id => '123',
363 );
364
365 $db_obj = SL::DB::BackgroundJob->new();
366 $db_obj->set_data(%data);
367 $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
368
369 $err_msg = '';
370 eval { $ret = $job->run($db_obj);  1; } or do {$err_msg = $@};
371 ok($err_msg =~ '^No valid part found by given part id', 'invalid part id detected');
372
373 #####
374
375 $part = new_service(partnumber => 'Serv1', unit => 'Std', obsolete => 1)->save;
376 %data = (
377   part_id => $part->id,
378 );
379
380 $db_obj = SL::DB::BackgroundJob->new();
381 $db_obj->set_data(%data);
382 $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
383
384 $err_msg = '';
385 eval { $ret = $job->run($db_obj);  1; } or do {$err_msg = $@};
386 ok($err_msg =~ '^No valid part found by given part id', 'obsolete part detected');
387
388 #####
389
390 %data = (
391   project_id => 123,
392 );
393
394 $db_obj = SL::DB::BackgroundJob->new();
395 $db_obj->set_data(%data);
396 $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
397
398 $err_msg = '';
399 eval { $ret = $job->run($db_obj);  1; } or do {$err_msg = $@};
400 ok($err_msg =~ '^No valid project found by given project id', 'invalid project id detected');
401
402 #####
403
404 $project = create_project(projectnumber => 'p1', description => 'Project 1', valid => 0)->save;
405 %data = (
406   project_id => $project->id,
407 );
408
409 $db_obj = SL::DB::BackgroundJob->new();
410 $db_obj->set_data(%data);
411 $job    = SL::BackgroundJob::ConvertTimeRecordings->new;
412
413 $err_msg = '';
414 eval { $ret = $job->run($db_obj);  1; } or do {$err_msg = $@};
415 ok($err_msg =~ '^No valid project found by given project id', 'invalid project detected');
416
417 #####
418
419 clear_up();
420
421
422 ########################################
423
424 $::locale = $old_locale;
425
426 1;
427
428 #####
429 # vim: ft=perl
430 # set emacs to perl mode
431 # Local Variables:
432 # mode: perl
433 # End: