1 use Test::More tests => 52;
8 use Support::TestSetup;
11 use Rose::DB::Object::Helpers qw(forget_related);
13 use SL::DB::BackgroundJob;
14 use SL::DB::DeliveryOrder;
16 use_ok 'SL::BackgroundJob::ConvertTimeRecordings';
18 use SL::Dev::ALL qw(:ALL);
20 Support::TestSetup::login();
23 foreach (qw(TimeRecording OrderItem Order DeliveryOrder Project Part Customer RecordLink)) {
24 "SL::DB::Manager::${_}"->delete_all(all => 1);
26 SL::DB::Manager::Employee->delete_all(where => [ '!login' => 'unittests' ]);
29 ########################################
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');
39 ########################################
40 # two time recordings, one order linked with project_id in time recording entry
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;
46 # sales order with globalproject_id
47 my $sales_order = create_sales_order(
49 customer => $customer,
50 globalproject => $project,
52 orderitems => [ create_order_item(part => $part, qty => 3, sellprice => 70), ]
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,
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,
73 from_date => '01.01.2021',
74 to_date => '30.04.2021',
76 my $db_obj = SL::DB::BackgroundJob->new();
77 $db_obj->set_data(%data);
78 my $job = SL::BackgroundJob::ConvertTimeRecordings->new;
79 my $ret = $job->run($db_obj);
81 is_deeply($job->{job_errors}, [], 'no errros');
82 like($ret, qr{^Number of delivery orders created: 1}, 'one delivery order created');
84 my $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
85 is(scalar @$linked_dos, 1, 'one delivery order linked to order');
86 is($linked_dos->[0]->globalproject_id, $sales_order->globalproject_id, 'project ids match');
88 my $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
89 is(scalar @$linked_items, 1, 'one delivery order item linked to order item');
90 is($linked_items->[0]->qty*1, 3, 'qty in delivery order');
91 is($linked_items->[0]->base_qty*1, 3, 'base_qty in delivery order');
93 # reload order and orderitems to get changes to deliverd and ship
94 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
97 ok($sales_order->delivered, 'related order is delivered');
98 is($sales_order->items->[0]->ship*1, 3, 'ship in related order');
103 ########################################
104 # two time recordings, one order linked with project_id in time recording entry
105 # unit in order is 'min', but part is 'Std'
106 ########################################
107 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
108 $project = create_project(projectnumber => 'p1', description => 'Project 1');
109 $customer = new_customer()->save;
111 $sales_order = create_sales_order(
113 customer => $customer,
114 globalproject => $project,
116 orderitems => [ create_order_item(part => $part, qty => 180, unit => 'min', sellprice => 70), ]
119 @time_recordings = ();
120 push @time_recordings, new_time_recording(
121 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 10),
122 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 10),
123 customer => $customer,
127 push @time_recordings, new_time_recording(
128 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 12, minute => 10),
129 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 14, minute => 10),
130 customer => $customer,
137 from_date => '01.04.2021',
138 to_date => '30.04.2021',
140 $db_obj = SL::DB::BackgroundJob->new();
141 $db_obj->set_data(%data);
142 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
143 $ret = $job->run($db_obj);
145 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
146 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
147 is($linked_items->[0]->qty*1, 3, 'different units: qty in delivery order');
148 is($linked_items->[0]->base_qty*1, 3, 'different units: base_qty in delivery order');
150 # reload order and orderitems to get changes to deliverd and ship
151 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
154 ok($sales_order->delivered, 'different units: related order is delivered');
155 is($sales_order->items->[0]->ship*1, 180, 'different units: ship in related order');
160 ########################################
161 # two time recordings, one order linked with project_id in time recording entry
162 # unit in order is 'Std', but part is 'min'
163 ########################################
164 $part = new_service(partnumber => 'Serv1', unit => 'min')->save;
165 $project = create_project(projectnumber => 'p1', description => 'Project 1');
166 $customer = new_customer()->save;
168 $sales_order = create_sales_order(
170 customer => $customer,
171 globalproject => $project,
173 orderitems => [ create_order_item(part => $part, qty => 2, unit => 'Std', sellprice => 70), ]
176 @time_recordings = ();
177 push @time_recordings, new_time_recording(
178 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 10),
179 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 10),
180 customer => $customer,
184 push @time_recordings, new_time_recording(
185 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 12, minute => 10),
186 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 13, minute => 10),
187 customer => $customer,
194 from_date => '01.04.2021',
195 to_date => '30.04.2021',
197 $db_obj = SL::DB::BackgroundJob->new();
198 $db_obj->set_data(%data);
199 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
200 $ret = $job->run($db_obj);
202 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
203 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
204 is($linked_items->[0]->qty*1, 2, 'different units 2: qty in delivery order');
205 is($linked_items->[0]->base_qty*1, 120, 'different units 2: base_qty in delivery order');
207 # reload order and orderitems to get changes to deliverd and ship
208 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
211 ok($sales_order->delivered, 'different units 2: related order is delivered');
212 is($sales_order->items->[0]->ship*1, 2, 'different units 2: ship in related order');
217 ########################################
218 # two time recordings, one with start/end one with date/duration
219 ########################################
220 $part = new_service(partnumber => 'Serv1', unit => 'min')->save;
221 $customer = new_customer()->save;
223 @time_recordings = ();
224 push @time_recordings, new_time_recording(
225 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 10),
226 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 10),
227 customer => $customer,
231 push @time_recordings, new_time_recording(
232 date => DateTime->new(year => 2021, month => 4, day => 19),
236 customer => $customer,
242 from_date => '01.04.2021',
243 to_date => '30.04.2021',
245 $db_obj = SL::DB::BackgroundJob->new();
246 $db_obj->set_data(%data);
247 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
248 $ret = $job->run($db_obj);
250 my $dos = SL::DB::Manager::DeliveryOrder->get_all(where => [customer_id => $customer->id]);
251 is($dos->[0]->items->[0]->qty*1, 180/60, 'date/duration and start/end: qty in delivery order');
252 is($dos->[0]->items->[0]->base_qty*1, 180, 'date/duration and start/end2: base_qty in delivery order');
257 ########################################
258 # time recording, linked with order_id
259 ########################################
260 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
261 $customer = new_customer()->save;
263 # sales order with globalproject_id
264 $sales_order = create_sales_order(
266 customer => $customer,
268 orderitems => [ create_order_item(part => $part, qty => 3, sellprice => 70), ]
271 @time_recordings = ();
272 push @time_recordings, new_time_recording(
273 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 5),
274 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 5),
275 customer => $customer,
276 order => $sales_order,
282 from_date => '01.04.2021',
283 to_date => '30.04.2021',
284 customernumbers => [$customer->number],
286 $db_obj = SL::DB::BackgroundJob->new();
287 $db_obj->set_data(%data);
288 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
289 $ret = $job->run($db_obj);
291 is_deeply($job->{job_errors}, [], 'no errros');
292 like($ret, qr{^Number of delivery orders created: 1}, 'linked by order_id: one delivery order created');
294 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
295 is(scalar @$linked_dos, 1, 'linked by order_id: one delivery order linked to order');
297 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
298 is(scalar @$linked_items, 1, 'linked by order_id: one delivery order item linked to order item');
299 is($linked_items->[0]->qty*1, 1, 'linked by order_id: qty in delivery order');
300 is($linked_items->[0]->base_qty*1, 1, 'linked by order_id: base_qty in delivery order');
302 # reload order and orderitems to get changes to deliverd and ship
303 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
306 is($sales_order->items->[0]->ship*1, 1, 'linked by order_id: ship in related order');
311 ########################################
312 # override project and part
313 ########################################
314 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
315 my $part2 = new_service(partnumber => 'Serv2', unit => 'min')->save;
316 $project = create_project(projectnumber => 'p1', description => 'Project 1');
317 my $project2 = create_project(projectnumber => 'p2', description => 'Project 2');
318 $customer = new_customer()->save;
320 $sales_order = create_sales_order(
322 customer => $customer,
323 globalproject => $project,
325 orderitems => [ create_order_item(part => $part, qty => 180, unit => 'min', sellprice => 70), ]
327 my $sales_order2 = create_sales_order(
329 customer => $customer,
330 globalproject => $project,
332 orderitems => [ create_order_item(part => $part2, qty => 180, unit => 'min', sellprice => 70), ]
336 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 10),
337 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 10),
338 customer => $customer,
343 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 10),
344 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 12, minute => 10),
345 customer => $customer,
346 project => $project2,
350 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 12, minute => 10),
351 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 13, minute => 10),
352 customer => $customer,
357 from_date => '01.04.2021',
358 to_date => '30.04.2021',
359 override_part_id => $part->id,
360 override_project_id => $project->id,
362 $db_obj = SL::DB::BackgroundJob->new();
363 $db_obj->set_data(%data);
364 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
365 $ret = $job->run($db_obj);
367 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
368 is($linked_dos->[0]->globalproject_id, $project->id, 'overriden part and project: project in delivery order');
370 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
371 is($linked_items->[0]->qty*1, 3, 'overriden part and project: qty in delivery order');
372 is($linked_items->[0]->base_qty*1, 3, 'overriden part and project: base_qty in delivery order');
373 is($linked_items->[0]->parts_id, $part->id, 'overriden part and project: part id');
375 my $linked_dos2 = $sales_order2->linked_records(to => 'DeliveryOrder');
376 is(scalar @$linked_dos2, 0, 'overriden part and project: no delivery order for unused order');
378 # reload order and orderitems to get changes to deliverd and ship
379 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
381 Rose::DB::Object::Helpers::forget_related($sales_order2, 'orderitems');
384 is($sales_order ->items->[0]->ship||0, 180, 'overriden part and project: ship in related order');
385 is($sales_order2->items->[0]->ship||0, 0, 'overriden part and project: ship in not related order');
390 ########################################
391 # default project and part
392 ########################################
393 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
394 $project = create_project(projectnumber => 'p1', description => 'Project 1');
395 $customer = new_customer()->save;
397 $sales_order = create_sales_order(
399 customer => $customer,
400 globalproject => $project,
402 orderitems => [ create_order_item(part => $part, qty => 180, unit => 'min', sellprice => 70), ]
406 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 10),
407 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 11, minute => 40),
408 customer => $customer,
413 from_date => '01.04.2021',
414 to_date => '30.04.2021',
415 default_part_id => $part->id,
416 default_project_id => $project->id,
418 $db_obj = SL::DB::BackgroundJob->new();
419 $db_obj->set_data(%data);
420 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
421 $ret = $job->run($db_obj);
423 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
424 is($linked_dos->[0]->globalproject_id, $project->id, 'default and project: project in delivery order');
426 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
427 is($linked_items->[0]->qty*1, 1.5, 'default part and project: qty in delivery order');
428 is($linked_items->[0]->base_qty*1, 1.5, 'default part and project: base_qty in delivery order');
429 is($linked_items->[0]->parts_id, $part->id, 'default part and project: part id');
431 # reload order and orderitems to get changes to deliverd and ship
432 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
435 is($sales_order->items->[0]->ship*1, 90, 'default part and project: ship in related order');
440 ########################################
442 ########################################
443 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
444 $customer = new_customer()->save;
446 $sales_order = create_sales_order(
448 customer => $customer,
450 orderitems => [ create_order_item(part => $part, qty => 3, sellprice => 70), ]
453 @time_recordings = ();
454 push @time_recordings, new_time_recording(
455 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 0),
456 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 6),
457 customer => $customer,
458 order => $sales_order,
463 from_date => '01.01.2021',
464 to_date => '30.04.2021',
468 $db_obj = SL::DB::BackgroundJob->new();
469 $db_obj->set_data(%data);
470 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
471 $ret = $job->run($db_obj);
473 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
474 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
475 is($linked_items->[0]->qty*1, 0.25, 'rounding to quarter hour: qty in delivery order');
476 is($linked_items->[0]->base_qty*1, 0.25, 'rounding to quarter hour: base_qty in delivery order');
478 # reload order and orderitems to get changes to deliverd and ship
479 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
482 is($sales_order->items->[0]->ship*1, 0.25, 'rounding to quarter hour: ship in related order');
487 ########################################
489 ########################################
490 $part = new_service(partnumber => 'Serv1', unit => 'Std')->save;
491 $customer = new_customer()->save;
493 $sales_order = create_sales_order(
495 customer => $customer,
497 orderitems => [ create_order_item(part => $part, qty => 3, sellprice => 70), ]
500 @time_recordings = ();
501 push @time_recordings, new_time_recording(
502 start_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 0),
503 end_time => DateTime->new(year => 2021, month => 4, day => 19, hour => 10, minute => 6),
504 customer => $customer,
505 order => $sales_order,
510 from_date => '01.01.2021',
511 to_date => '30.04.2021',
515 $db_obj = SL::DB::BackgroundJob->new();
516 $db_obj->set_data(%data);
517 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
518 $ret = $job->run($db_obj);
520 $linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
521 $linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
522 is($linked_items->[0]->qty*1, 0.1, 'no rounding: qty in delivery order');
523 is($linked_items->[0]->base_qty*1, 0.1, 'no rounding: base_qty in delivery order');
525 # reload order and orderitems to get changes to deliverd and ship
526 Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
529 is($sales_order->items->[0]->ship*1, 0.1, 'no rounding: ship in related order');
534 ########################################
535 # are wrong params detected?
536 ########################################
538 from_date => 'x01.04.2021',
540 $db_obj = SL::DB::BackgroundJob->new();
541 $db_obj->set_data(%data);
542 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
545 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
546 ok($err_msg =~ '^Cannot convert date.', 'wrong date string detected');
550 $customer = new_customer()->save;
552 customernumbers => ['a fantasy', $customer->number],
555 $db_obj = SL::DB::BackgroundJob->new();
556 $db_obj->set_data(%data);
557 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
560 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
561 ok($err_msg =~ '^Not all customer numbers are valid', 'wrong customer number detected');
566 customernumbers => '123',
569 $db_obj = SL::DB::BackgroundJob->new();
570 $db_obj->set_data(%data);
571 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
574 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
575 ok($err_msg =~ '^Customer numbers must be given in an array', 'wrong customer number data type detected');
580 override_part_id => '123',
583 $db_obj = SL::DB::BackgroundJob->new();
584 $db_obj->set_data(%data);
585 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
588 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
589 ok($err_msg =~ '^No valid part found by given override part id', 'invalid part id detected');
593 $part = new_service(partnumber => 'Serv1', unit => 'Std', obsolete => 1)->save;
595 override_part_id => $part->id,
598 $db_obj = SL::DB::BackgroundJob->new();
599 $db_obj->set_data(%data);
600 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
603 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
604 ok($err_msg =~ '^No valid part found by given override part id', 'obsolete part detected');
609 override_project_id => 123,
612 $db_obj = SL::DB::BackgroundJob->new();
613 $db_obj->set_data(%data);
614 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
617 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
618 ok($err_msg =~ '^No valid project found by given override project id', 'invalid project id detected');
622 $project = create_project(projectnumber => 'p1', description => 'Project 1', valid => 0)->save;
624 override_project_id => $project->id,
627 $db_obj = SL::DB::BackgroundJob->new();
628 $db_obj->set_data(%data);
629 $job = SL::BackgroundJob::ConvertTimeRecordings->new;
632 eval { $ret = $job->run($db_obj); 1; } or do {$err_msg = $@};
633 ok($err_msg =~ '^No valid project found by given override project id', 'invalid project detected');
640 ########################################
642 $::locale = $old_locale;
648 # set emacs to perl mode